# import gdal
# from gdal import ogr
# from gdal import osr
from tqdm import tqdm
from time import time
from multiprocessing import Pool
# import pypinyin
# from pypinyin import pinyin, lazy_pinyin
import os
import cv2
import zipfile
import json
import shutil
import numpy as np
import re
import math
import base64
import sqlite3


# gdal.UseExceptions()
# ogr.UseExceptions()
# ogr.RegisterAll()
# gdal.SetConfigOption("GDAL_FILENAME_IS_UTF8", "YES")
# gdal.SetConfigOption("SHAPE_ENCODING", "GBK")


class TensorPU:
	"""
	通用工具
	"""

	def __init__(self, arr3d=None):
		self.arr3d = arr3d
	
	@staticmethod
	def MinMaxNormalization(arr3d, minmaxs):
		"""（value-min）/（max-min）,arr3d矩阵共三个纬度"""
		(channls, height, width) = arr3d.shape
		rearr3d = None
		for index in range(channls):
			arr2d = arr3d[index::]
			[minvalue, maxvalue] = minmaxs[index]
			normatrix = (arr2d - minvalue) / (maxvalue - minvalue)
			if index == 0:
				rearr3d = normatrix
			else:
				rearr3d = np.concatenate((rearr3d, normatrix), axis=0)
				if index == channls - 1:
					print("minmax标准化完成！")
					return rearr3d
	
	@staticmethod
	def Arr2dMinMaxNormalization(arr2d, minvalue, maxvalue):
		"""（value-min）/（max-min）,arr3d矩阵共三个纬度"""
		if minvalue == maxvalue:
			(height, width) = arr2d.shape
			return np.ones((height, width)).astype(float)
		else:
			arr2d = arr2d.astype(float)
			return (arr2d - minvalue) / (maxvalue - minvalue)
	
	@staticmethod
	def MergeMatrixs(arr3dfirst, arr3dsecond):
		"""
		multiple matrix在第0纬度合并,矩阵共三个纬度
		:param arr3dfirst:  输入的数组
		:param arr3dsecond:
		:return:
		"""
		if arr3dfirst.shape[0] != arr3dsecond.shape[0]:
			print("矩阵在第0维度大小不同！，矩阵合并失败")
			return None
		else:
			(channls, height, width) = arr3dfirst.shape
			(channlst, heightt, widtht) = arr3dsecond.shape
			fitarr3d = arr3dfirst.reshape((channls, 1, height * width))
			fitarr3dtmp = arr3dsecond.reshape((channlst, 1, heightt * widtht))
			splicingarr3d = np.concatenate((fitarr3d, fitarr3dtmp), axis=2)
			print("矩阵拼接完成！")
			return splicingarr3d
	
	@staticmethod
	def DataChecking(arr3d):
		illegalvaluelocation = np.where(arr3d <= 0)
		location1darr = illegalvaluelocation[0]
		location1darrsize = location1darr.shape[0]
		if location1darrsize:
			print("存在数据异常！")
			return illegalvaluelocation
		else:
			print("未出现异常数据！")
			return None
	
	@staticmethod
	def RightPanMattrix(arr3d, channelindexpanvalues):
		arr3dcp = arr3d.copy()
		for channelindexpanvalue in channelindexpanvalues:
			[channelindex, panvalue] = channelindexpanvalue
			arr2d = arr3dcp[channelindex, :, :]
			arr3dcp[channelindex::] = arr2d + panvalue
		return arr3dcp
	
	@staticmethod
	def TruncationMattrix(arr3d, channelindextopbottomvalues):
		arr3dcp = arr3d.copy()
		for channelindextopbottomvalue in channelindextopbottomvalues:
			[channelindex, bottomvalue, topvalue] = channelindextopbottomvalue
			arr2d = arr3dcp[channelindex, :, :]
			topvaluelocation = np.where(arr2d >= topvalue)
			bottomvaluelocation = np.where(arr2d <= bottomvalue)
			arr2d[topvaluelocation] = topvalue
			arr2d[bottomvaluelocation] = bottomvalue
		return arr3dcp
	
	@staticmethod
	def Arr2dAddArr2d(arr2dfirst, arr2dsecond):
		rearr2d = arr2dfirst + arr2dsecond
		return rearr2d
	
	@staticmethod
	def Arr2dsToNDVI(redarr, nearredarr):
		redarr = redarr.astype(np.float32)
		nearredarr = nearredarr.astype(np.float32)
		redarrzerolocation = np.where(redarr == 0)
		nearredarrzerolocation = np.where(nearredarr == 0)
		redarr[redarrzerolocation] = None
		nearredarr[nearredarrzerolocation] = None
		ndvi = (nearredarr - redarr) / (nearredarr + redarr)
		return ndvi


class Sqlite3PU:
	DBdir = r"/home/fyy_dapeng/Sqlite3DB"
	DBname = r"RasterInfo.db"
	TBname = r"Sentinel2Raster"
	FDname = r"RasterNumber"
	tbheader = [
		["RasterNumber", "varchar(10)"],
		["XPixelSize", "integer"],
		["YPixelSize", "integer"],
		["Geotransfrom_0", "real"],
		["Geotransfrom_1", "real"],
		["Geotransfrom_2", "real"],
		["Geotransfrom_3", "real"],
		["Geotransfrom_4", "real"],
		["Geotransfrom_5", "real"]
	]
	datatype_NULL = "NULL"
	datatype_INTEGER = "INTEGER"
	datatype_REAL = "REAL"
	datatype_TEXT = "TEXT"
	
	def __init__(self):
		pass
	
	def CreateDB(self, dbdir=None, dbname=None, flage=False):
		"""创建新的数据库"""
		if dbdir is None:
			dbdir = self.DBdir
		if dbname is None:
			dbname = self.DBname
		dbpath = os.path.join(dbdir, dbname)
		if os.path.exists(dbpath):
			if flage:
				print("同名数据库存在，删除旧数据库，创建新数据库！")
				os.remove(dbpath)
				conn = sqlite3.connect(dbpath)
				cursor = conn.cursor()
				cursor.close()
				conn.commit()
				conn.close()
			else:
				pass
		else:
			conn = sqlite3.connect(dbpath)
			cursor = conn.cursor()
			cursor.close()
			conn.commit()
			conn.close()
		return
	
	def CreateTabel(self, dbpath=None, tbname=None, tbheader=None, flage=False):
		"""创建新的表"""
		if dbpath is None:
			dbpath = os.path.join(self.DBdir, self.DBname)
		if tbname is None:
			tbname = self.TBname
		if tbheader is None:
			tbheader = self.tbheader
		tabelnames = self.GetTables(dbpath)
		if tabelnames.count((tbname,)) == 1:
			if flage:
				print("同名表存在,删除旧表，创建新表！")
				self.DropTable(dbpath, tbname)
				filedstrs = [" ".join(filedinfo) for filedinfo in tbheader]
				filedsstr = " NOT NULL,".join(filedstrs)
				sql = "create table if not exists %s(ID integer primary key,%s)" \
				      % (tbname, filedsstr)
				conn = sqlite3.connect(dbpath)
				cursor = conn.cursor()
				cursor.execute(sql)
				cursor.close()
				conn.commit()
				conn.close()
			else:
				pass
		else:
			filedstrs = [" ".join(filedinfo) for filedinfo in tbheader]
			filedsstr = " NOT NULL,".join(filedstrs)
			sql = "create table if not exists %s(ID integer primary key,%s)" \
			      % (tbname, filedsstr)
			conn = sqlite3.connect(dbpath)
			cursor = conn.cursor()
			cursor.execute(sql)
			cursor.close()
			conn.commit()
			conn.close()
		return
	
	# @staticmethod
	# def TableAddField(dbpath, tbname, fields):
	# 	conn = sqlite3.connect(dbpath)
	# 	cursor = conn.cursor()
	# 	for filed in fileds:
	# 		fieldname, fieldtype = filed
	# 		sql = "ALTER TABLE %s ADD %s %s;" % (tbname, fieldtype, fieldname)
	# 	cursor.execute(sql)
	# 	tabelstructure = cursor.fetchall()
	# 	cursor.close()
	# 	conn.commit()
	# 	conn.close()
	# 	return
	
	def GetTableStructure(self, dbpath=None, tbname=None):
		"""获得指定数据库表表头"""
		if dbpath is None:
			dbpath = os.path.join(self.DBdir, self.DBname)
		if tbname is None:
			tbname = self.TBname
		conn = sqlite3.connect(dbpath)
		cursor = conn.cursor()
		sql = "PRAGMA table_info(%s)" % tbname
		cursor.execute(sql)
		tabelstructure = cursor.fetchall()
		cursor.close()
		conn.commit()
		conn.close()
		return tabelstructure
	
	def GetTables(self, dbpath=None):
		"""获取指定数据库所有表名"""
		if dbpath is None:
			dbpath = os.path.join(self.DBdir, self.DBname)
		conn = sqlite3.connect(dbpath)
		cursor = conn.cursor()
		sql = "select name from sqlite_master where type='table' order by name"
		cursor.execute(sql)
		tabelnames = cursor.fetchall()
		cursor.close()
		conn.commit()
		conn.close()
		return tabelnames
	
	def DropTable(self, dbpath=None, tbname=None):
		if dbpath is None:
			dbpath = dbpath = os.path.join(self.DBdir, self.DBname)
		if tbname is None:
			tbname = self.TBname
		conn = sqlite3.connect(dbpath)
		cursor = conn.cursor()
		sql = "DROP TABLE %s" % tbname
		cursor.execute(sql)
		cursor.close()
		conn.commit()
		conn.close()
		return
	
	def InsertRecording(self, datalist, dbpath=None, tbname=None):
		if dbpath is None:
			dbpath = dbpath = os.path.join(self.DBdir, self.DBname)
		if tbname is None:
			tbname = self.TBname
		fileds = self.GetTableStructure(dbpath, tbname)
		'''去除主键字段'''
		filednames = [filed[1] for filed in fileds[1:]]
		noprimarykeyc = len(filednames)
		fileddictkeys = ["?" for index in range(noprimarykeyc)]
		fileddictstr, filednamestr = ",".join(fileddictkeys), ",".join(
			filednames)
		sql = "INSERT INTO %s(%s) VALUES(%s);" % (
			tbname, filednamestr, fileddictstr)
		for data in datalist:
			conn = sqlite3.connect(dbpath)
			cursor = conn.cursor()
			cursor.execute(sql, data)
			cursor.close()
			conn.commit()
			conn.close()
		return
	
	def SelectRecording(self, dbpath=None, tbname=None, fdname=None,
	                    fdvalue=None):
		if dbpath is None:
			dbpath = dbpath = os.path.join(self.DBdir, self.DBname)
		if tbname is None:
			tbname = self.TBname
		if fdname is None:
			fdname = self.FDname
		sql = "SELECT * FROM %s WHERE %s=?;" % (tbname, fdname)
		conn = sqlite3.connect(dbpath)
		cursor = conn.cursor()
		cursor.execute(sql, [fdvalue])
		selectresult = cursor.fetchall()
		cursor.close()
		conn.commit()
		conn.close()
		return selectresult
	
	@classmethod
	def SelectRecordings(cls, dbpath, tbname, fddicts):
		filedstrs = ["%s=?" % fddicts[i][0] for i in range(len(fddicts))]
		valuesdict = [fddicts[i][1] for i in range(len(fddicts))]
		sqlstr = " and ".join(filedstrs)
		sql = "SELECT * FROM %s WHERE %s;" % (tbname, sqlstr)
		conn = sqlite3.connect(dbpath)
		cursor = conn.cursor()
		cursor.execute(sql, valuesdict)
		result = cursor.fetchall()
		cursor.close()
		conn.commit()
		conn.close()
		return result
	
	def PrintTable(self, dbpath=None, tbname=None):
		if dbpath is None:
			dbpath = dbpath = os.path.join(self.DBdir, self.DBname)
		if tbname is None:
			tbname = self.TBname
		sql = "SELECT * FROM %s;" % tbname
		fileds = self.GetTableStructure(dbpath, tbname)
		print(" ".join([filed[1] for filed in fileds]))
		conn = sqlite3.connect(dbpath)
		cursor = conn.cursor()
		cursor.execute(sql)
		for it in cursor:
			item = list(it)
			print("        ".join([str(i) for i in item]), '\n')
		cursor.close()
		conn.commit()
		conn.close()
		return


TPU = TensorPU()


# class ShpToRaster:
# 	fieldindex = 9
# 	fieldname = "BL"
# 	maxthreshold = 0.9
# 	minthreshold = 0.01
# 	driver = gdal.GetDriverByName("GTiff")
# 	datetype = gdal.GDT_UInt16
	
# 	def __init__(self, raspath, shpdir, layername, outdir):
# 		self.raspath = raspath
# 		self.shpdir = shpdir
# 		self.layername = layername
# 		self.outdir = outdir
# 		self.layerpositivename = self.layername + r"_Negative"
# 		self.layernegativename = self.layername + r"_Positive"
# 		self.dstraspath = os.path.join(self.outdir, layername + r".tif")
	
# 	def GetRasterFrameGeometry(self):
# 		ras = gdal.Open(self.raspath)
# 		ring = ogr.Geometry(ogr.wkbLinearRing)
# 		width = ras.RasterXSize
# 		height = ras.RasterYSize
# 		geotrs = ras.GetGeoTransform()
# 		frame = [
# 			[geotrs[0], geotrs[3]],
# 			[geotrs[0], geotrs[3] + height * geotrs[5]],
# 			[geotrs[0] + width * geotrs[1], geotrs[3] + height * geotrs[5]],
# 			[geotrs[0] + width * geotrs[1], geotrs[3]]]
# 		for point in frame:
# 			ring.AddPoint(point[0], point[1])
# 		ring.CloseRings()
# 		polygon = ogr.Geometry(ogr.wkbPolygon)
# 		polygon.AddGeometry(ring)
# 		del ras
# 		return polygon
	
# 	def GetRasterInfo(self):
# 		ras = gdal.Open(self.raspath)
# 		driver = ras.GetDriver()
# 		width = ras.RasterXSize
# 		height = ras.RasterYSize
# 		geotrs = ras.GetGeoTransform()
# 		proj = ras.GetProjection()
# 		srs = ras.GetSpatialRef()
# 		del ras
# 		return [driver, width, height, geotrs, proj, srs]
	
# 	def SelectGoalLayerPositive(self):
# 		datasource = ogr.Open(self.shpdir, 1)
# 		if datasource.GetLayerByName(self.layerpositivename) is not None:
# 			datasource.DeleteLayer(self.layerpositivename)
# 		layer = datasource.GetLayerByName(self.layername)
# 		select = "%s >= %f" % (self.fieldname, self.maxthreshold)
# 		layer.SetAttributeFilter(select)
# 		datasource.CopyLayer(layer, self.layerpositivename)
# 		datasource.Destroy()
# 		# layer.SetAttributeFilter(None)
# 		return print("获取到目标字段新图层！")
	
# 	def SelectGoalLayerNegative(self):
# 		datasource = ogr.Open(self.shpdir, 1)
# 		if datasource.GetLayerByName(self.layernegativename) is not None:
# 			datasource.DeleteLayer(self.layernegativename)
# 		layer = datasource.GetLayerByName(self.layername)
# 		select = "%s <= %f" % (self.fieldname, self.minthreshold)
# 		layer.SetAttributeFilter(select)
# 		datasource.CopyLayer(layer, self.layernegativename)
# 		datasource.Destroy()
# 		# layer.SetAttributeFilter(None)
# 		return print("获取到目标字段新图层！")
	
# 	def GetFieldAll(self):
# 		datasource = ogr.Open(self.shpdir)
# 		layer = datasource.GetLayerByName(self.layername)
# 		featruredefn = layer.GetLayerDefn()
# 		fieldc = featruredefn.GetFieldCount()
# 		for index in range(fieldc):
# 			fielddefn = featruredefn.GetFieldDefn(index)
# 			fieldname = fielddefn.GetName()
# 			fieldindex = featruredefn.GetFieldIndex(fieldname)
# 			print(fieldname, fieldindex)
# 			fielddefn.Destroy()
# 		featruredefn.Destroy()
# 		datasource.Destroy()
# 		return
	
# 	def GetRasterFile(self):
# 		if os.path.exists(self.dstraspath):
# 			os.remove(self.dstraspath)
		
# 		self.SelectGoalLayerNegative()
# 		self.SelectGoalLayerPositive()
		
# 		[driver, width, height, geotrs, proj, srs] = self.GetRasterInfo()
# 		datasource = ogr.Open(self.shpdir, 1)
		
# 		layerpositive = datasource.GetLayerByName(self.layerpositivename)
# 		layernegative = datasource.GetLayerByName(self.layernegativename)
		
# 		dataset = driver.Create(self.dstraspath, width, height, 2,
# 		                        self.datetype)
# 		dataset.SetGeoTransform(geotrs)
# 		dataset.SetProjection(proj)
# 		dataset.SetSpatialRef(srs)
		
# 		bandpositive = dataset.GetRasterBand(1)
# 		bandpositive.SetNoDataValue(0)
# 		bandpositive.FlushCache()
# 		# gdal.RasterizeLayer(dataset, [1], layer, options=["ATTRIBUTE=BL"])
# 		gdal.RasterizeLayer(dataset, [1], layerpositive, burn_values=[1])
		
# 		bandnegative = dataset.GetRasterBand(2)
# 		bandnegative.SetNoDataValue(0)
# 		bandnegative.FlushCache()
# 		gdal.RasterizeLayer(dataset, [2], layernegative, burn_values=[1])
# 		del dataset
		
# 		datasource.DeleteLayer(self.layerpositivename)
# 		datasource.DeleteLayer(self.layernegativename)
# 		datasource.Destroy()
# 		return print("获取到目标字段新栅格！")


# class ShapePU:
# 	ogr.UseExceptions()
# 	ogr.RegisterAll()
# 	gdal.SetConfigOption("GDAL_FILENAME_IS_UTF8", "YES")
# 	gdal.SetConfigOption("SHAPE_ENCODING", "GBK")
# 	drivername = 'ESRI Shapefile'
# 	driverstyletable = None
# 	layerstyletable = None
# 	geomtype = ogr.wkbPolygon
# 	wgs84srsdefn = (
# 			"GEOGCS[\"WGS 84\"," +
# 			"DATUM[\"World Geodetic System 1984\"," +
# 			"SPHEROID[\"WGS 84\",6378137,298.257223563]]," +
# 			"PRIMEM[\"Greenwich\",0]," +
# 			"UNIT[\"degree\",0.0174532925199433]," +
# 			"AXIS[\"Longitude\",EAST],AXIS[\"Latitude\",NORTH]]"
# 	)
# 	datatype = gdal.GDT_UInt16
	
# 	def __init__(self):
# 		pass
	
# 	@staticmethod
# 	def GetSrsw(dsname, layername=None):
# 		"""获取矢量文件指定土城坐标系对象， 并返回该对象为字符串"""
# 		ds = ogr.Open(dsname, 0)
# 		if layername is None:
# 			layer = ds.GetLayer()
# 		else:
# 			layer = ds.GetLayerByName(layername)
# 		srs = layer.GetSpatialRef()
# 		srsw = srs.ExportToWkt()
# 		ds.Destroy()
# 		return srsw
	
# 	@staticmethod
# 	def GetLayerName(dsname, layerid=0):
# 		"""获取矢量文件指定图层名"""
# 		ds = ogr.Open(dsname, 0)
# 		layer = ds.GetLayer(layerid)
# 		layername = layer.GetName()
# 		ds.Destroy()
# 		return layername
	
# 	@staticmethod
# 	def GetGeomeType(dsname, layername=None):
# 		"""获取矢量文件指定图层名"""
# 		ds = ogr.Open(dsname, 0)
# 		if layername is None:
# 			layer = ds.GetLayer()
# 		else:
# 			layer = ds.GetLayerByName(layername)
# 		geomtype = layer.GetGeomType()
# 		ds.Destroy()
# 		return geomtype
	
# 	@classmethod
# 	def JGeomClipShp(cls, jgeom, dsname, layername=None):
# 		"""用geometry裁剪shp指定图层，获得裁剪后的json格式的geometry列表"""
# 		jgeometrys = cls.ShpToETJGeometrys(dsname, layername)
# 		outgeometrys = []
# 		for jgeometry in jgeometrys:
# 			shpgeometry = ogr.CreateGeometryFromJson(jgeometry)
# 			wingeometry = ogr.CreateGeometryFromJson(jgeom)
# 			outgeometry = wingeometry.Intersection(shpgeometry)
# 			if not outgeometry.IsEmpty() and outgeometry is not None:
# 				outgeometrys.append(outgeometry.ExportToJson())
# 		return outgeometrys
	
# 	@staticmethod
# 	def GetFieldValue(dsname, lyname, flname):
# 		ds = ogr.Open(dsname)
# 		ly = ds.GetLayerByName(lyname)
# 		featurec = ly.FeatureCount()
# 		return
	
# 	@classmethod
# 	def CreateEmptyShp(cls, dsdir, dssign, layername=None, srsstr=None,
# 	                   layerdefn=None, geomtype=None, drivername=None):
# 		dsname = os.path.join(dsdir, dssign)
# 		if drivername is None:
# 			drivername = cls.drivername
# 		if os.path.exists(dsname):
# 			datasource = ogr.Open(dsname, 1)
# 		else:
# 			driver = ogr.GetDriverByName(drivername)
# 			datasource = driver.CreateDataSource(dsname)
# 			datasource.SetStyleTable(cls.driverstyletable)
# 		if srsstr is None:
# 			srs = osr.SpatialReference(wkt=cls.wgs84srsdefn)
# 		elif isinstance(srsstr, str):
# 			srs = osr.SpatialReference(wkt=srsstr)
# 		else:
# 			srs = srsstr
# 		if layername is None:
# 			layername = dssign
# 		if geomtype is None:
# 			geomtype = cls.geomtype
# 		if datasource.GetLayerByName(layername):
# 			datasource.DeleteLayer(layername)
# 		layer = datasource.CreateLayer(layername, srs=srs, geom_type=geomtype)
# 		if layerdefn is not None:
# 			for fielddefninfo in layerdefn:
# 				if len(fielddefninfo) == 2:
# 					[fieldname, fieldtype] = fielddefninfo
# 					fielddefn = ogr.FieldDefn(fieldname, fieldtype)
# 				else:
# 					[fieldname, fieldtype, fieldwidth] = fielddefninfo
# 					fielddefn = ogr.FieldDefn(fieldname, fieldtype)
# 					fieldDefn2.SetWidth(fieldwidth)
# 				layer.CreateField(fielddefn)
# 		layer.SetStyleTable(cls.layerstyletable)
# 		datasource.Destroy()
# 		return [dsname, layername]
	
# 	@staticmethod
# 	def ETJGeometrysSrsTransf(srcetjgeometrys, srcsrsstr, dstsrsstr):
# 		dstsrs = osr.SpatialReference(wkt=dstsrsstr)
# 		srcsrs = osr.SpatialReference(wkt=srcsrsstr)
# 		ct = osr.CreateCoordinateTransformation(srcsrs, dstsrs)
# 		etjgeometrys = []
# 		print("开始转换geometry的空间坐标。。。")
# 		for etjgeometry in tqdm(srcetjgeometrys):
# 			polygon = json.loads(etjgeometry)["coordinates"][0]
# 			srspolygon = []
# 			for point in polygon:
# 				srspolygon.append([
# 					ct.TransformPoint(point[1], point[0])[0],
# 					ct.TransformPoint(point[1], point[0])[1]])
# 			etjgeometry = json.dumps(
# 				{"type": "Polygon", "coordinates": [srspolygon]})
# 			etjgeometrys.append(etjgeometry)
# 		print("完成转换geometry的空间坐标！")
# 		return etjgeometrys
	
# 	@staticmethod
# 	def JGeometrySrsTransform(jgeometry, srcsrsw, dstsrsw):
# 		srcsrs = osr.SpatialReference(wkt=srcsrsw)
# 		dstsrs = osr.SpatialReference(wkt=dstsrsw)
# 		ct = osr.CreateCoordinateTransformation(srcsrs, dstsrs)
# 		geomdict = json.loads(jgeometry)
# 		polygon = geomdict["coordinates"][0]
# 		geomdict["coordinates"][0] = [
# 			ct.TransformPoint(point[1], point[0]) for point in polygon]
# 		jgeometry = json.dumps(geomdict)
# 		geometry = ogr.CreateGeometryFromJson(jgeometry)
# 		geometry.SwapXY()
# 		jgeometry = geometry.ExportToJson()
# 		return jgeometry
	
# 	@classmethod
# 	def ListToShp(cls, raspath, featurels, dsdir, dssign, layername):
# 		"""根据原始栅格仿射参数以及字段几何坐标对象列表生成shp"""
# 		ras = gdal.Open(raspath)
# 		geot = ras.GetGeoTransform()
# 		# srsw = ras.GetSpatialRef().ExportToWkt()
# 		srs = ras.GetSpatialRef()
# 		srsw = srs.ExportToWkt()
# 		print(srsw)
# 		del ras
# 		[dsname, layername] = cls.CreateEmptyShp(dsdir, dssign, layername, srsw)
# 		ds = ogr.Open(dsname, 1)
# 		layer = ds.GetLayerByName(layername)
# 		featuredefn = layer.GetLayerDefn()
# 		'''字段的名称以及类型设置，并在图层中添加该字段设置！'''
# 		fieldtype = ogr.OFTReal
# 		fieldname = "pre"
# 		fielddefn = ogr.FieldDefn(fieldname, fieldtype)
# 		layer.CreateField(fielddefn)
# 		'''循环处理'''
# 		for featurevaluearr in featurels:
# 			featurevalue = featurevaluearr.tolist()
# 			fieldvalue = featurevalue[-1]
# 			xypixels = featurevalue[:-1]
# 			xypixels = xypixels + [featurevalue[0], featurevalue[1]]
# 			polygon = [
# 				[xypixels[i] * geot[1] + geot[0],
# 				 xypixels[i + 1] * geot[5] + geot[3]]
# 				for i in range(0, len(xypixels), 2)]
# 			geometrydict = {"type": 'Polygon', "coordinates": [polygon]}
# 			geometryjson = json.dumps(geometrydict)
# 			geometry = ogr.CreateGeometryFromJson(geometryjson)
# 			feature = ogr.Feature(featuredefn)
# 			'''SetGeometry()与SetGeometryDirectly（）区别未知？'''
# 			feature.SetGeometryDirectly(geometry)
# 			feature.SetField(fieldname, fieldvalue)
# 			layer.CreateFeature(feature)
# 			feature.Destroy()
# 		ds.Destroy()
# 		return
	
# 	@classmethod
# 	def ListToShp_tif(cls, ras, featurels, dsdir, dssign, layername):
# 		"""根据原始栅格仿射参数以及字段几何坐标对象列表生成shp"""
# 		geot = ras.GetGeoTransform()
# 		# srsw = ras.GetSpatialRef().ExportToWkt()
# 		srs = ras.GetSpatialRef()
# 		srsw = srs.ExportToWkt()
# 		del ras
# 		[dsname, layername] = cls.CreateEmptyShp(dsdir, dssign, layername, srsw)
# 		ds = ogr.Open(dsname, 1)
# 		layer = ds.GetLayerByName(layername)
# 		featuredefn = layer.GetLayerDefn()
# 		'''字段的名称以及类型设置，并在图层中添加该字段设置！'''
# 		fieldtype = ogr.OFTReal
# 		fieldname = "pre"
# 		fielddefn = ogr.FieldDefn(fieldname, fieldtype)
# 		layer.CreateField(fielddefn)
# 		'''循环处理'''
# 		for featurevaluearr in featurels:
# 			featurevalue = featurevaluearr.tolist()
# 			fieldvalue = featurevalue[-1]
# 			xypixels = featurevalue[:-1]
# 			xypixels = xypixels + [featurevalue[0], featurevalue[1]]
# 			polygon = [
# 				[xypixels[i] * geot[1] + geot[0],
# 				 xypixels[i + 1] * geot[5] + geot[3]]
# 				for i in range(0, len(xypixels), 2)]
# 			geometrydict = {"type": 'Polygon', "coordinates": [polygon]}
# 			geometryjson = json.dumps(geometrydict)
# 			geometry = ogr.CreateGeometryFromJson(geometryjson)
# 			feature = ogr.Feature(featuredefn)
# 			'''SetGeometry()与SetGeometryDirectly（）区别未知？'''
# 			feature.SetGeometryDirectly(geometry)
# 			feature.SetField(fieldname, fieldvalue)
# 			layer.CreateFeature(feature)
# 			feature.Destroy()
# 		ds.Destroy()
# 		return
	
# 	@staticmethod
# 	def PolygonToJGeometry(polygon):
# 		"""xian'su"""
# 		ringgeometry = polygon + [polygon[0]]
# 		geometrydict = {"type": 'Polygon', "coordinates": [ringgeometry]}
# 		geometryjson = json.dumps(geometrydict)
# 		return geometryjson
	
# 	@staticmethod
# 	def ShpToJson(dsname, layername=0):
# 		gdal.SetConfigOption("GDAL_FILENAME_IS_UTF8", "YES")
# 		gdal.SetConfigOption("SHAPE_ENCODING", "GBK")
# 		datasource = ogr.Open(dsname)
# 		if layername == 0:
# 			layer = datasource.GetLayer(0)
# 		else:
# 			layer = datasource.GetLayerByName(layername)
# 		featuredicts = []
# 		featurec = layer.GetFeatureCount()
# 		print("开始提取shp文件中所有要素为json列表。。。")
# 		for index in tqdm(range(featurec)[:1000]):
# 			feature = layer.GetFeature(index)
			
# 			featuredict = feature.ExportToJson()
# 			print(featuredict)
# 			# t = featuredict.replace('u\'', '\'')
# 			# m = json.loads(t)
# 			# print(m)
# 			featuredicts.append(featuredict)
# 			feature.Destroy()
# 		datasource.Destroy()
# 		print("完成提取shp文件中所有要素为json列表！")
# 		return featuredicts
	
# 	@classmethod
# 	def ShpToSRSGeomShp(cls, dsname, layername, dsdir, dstsrs=None):
# 		"""获得指定的坐标系无字段的shp文件"""
# 		dssign = layername + r"_TSRS"
# 		dstdsname = os.path.join(dsdir, dssign)
# 		if os.path.exists(dstdsname):
# 			print(dstdsname, "该矢量文件存在，退出生成！")
# 			return [dstdsname, dssign]
# 		srcsrsw = cls.GetSrsw(dsname, layername)
# 		if dstsrs is None:
# 			dstsrs = osr.SpatialReference(wkt=cls.wgs84srsdefn)
# 		else:
# 			dstsrs = osr.SpatialReference(wkt=dstsrs)
# 		dstsrsw = dstsrs.ExportToWkt()
# 		[dstdsname, dstlayername] = cls.CreateEmptyShp(
# 			dsdir, dssign, srsstr=dstsrsw)
# 		etjgeometrys = cls.ShpToETJGeometrys(dsname, layername)
# 		print("开始转换geometry坐标。。。")
# 		jgeometrys = [
# 			cls.JGeometrySrsTransform(etjgeometry, srcsrsw, dstsrsw)
# 			for etjgeometry in tqdm(etjgeometrys)]
# 		print("完成转换geometry坐标！")
# 		cls.GeomsUpdataShp(dstdsname, dstlayername, jgeometrys)
# 		return [dstdsname, dstlayername]
	
# 	@staticmethod
# 	def ShpToETJGeometrys(dsname, layername=None):
# 		"""获取矢量文件所有json格式几何"""
# 		datasource = ogr.Open(dsname, 1)
# 		if layername is None:
# 			layer = datasource.GetLayer(0)
# 		else:
# 			layer = datasource.GetLayerByName(layername)
# 		featurec = layer.GetFeatureCount()
# 		features = [layer.GetFeature(i) for i in range(featurec)]
# 		etjgeometrys = [feature.geometry().ExportToJson() for feature in
# 		                features]
# 		datasource.Destroy()
# 		return etjgeometrys
	
# 	@staticmethod
# 	def GeomsUpdataShp(dsname, layername, etjgeometrys):
# 		datasource = ogr.Open(dsname, 1)
# 		layer = datasource.GetLayerByName(layername)
# 		featuredefn = layer.GetLayerDefn()
# 		print("开始更新shp文件。。。。。")
# 		for etjgeometry in tqdm(etjgeometrys):
# 			feature = ogr.Feature(featuredefn)
# 			geometry = ogr.CreateGeometryFromJson(etjgeometry)
# 			feature.SetGeometry(geometry)
# 			layer.CreateFeature(feature)
# 		datasource.Destroy()
# 		print("完成更新shp文件！")
# 		return
	
# 	@staticmethod
# 	def ShapeToRaster(raspath, dsname, rasdir, layername=None):
# 		"""根据栅格文件属性，把矢量文件修改为栅格文件,前提二者的坐标系相同"""
# 		ras = gdal.Open(raspath)
# 		width = ras.RasterXSize
# 		height = ras.RasterYSize
# 		geot = ras.GetGeoTransform()
# 		proj = ras.GetProjection()
# 		etwsrs = ras.GetSpatialRef().ExportToWkt()
# 		datatype = ras.GetRasterBand(1).DataType
# 		srs = osr.SpatialReference()
# 		srs.ImportFromWkt(etwsrs)
# 		del ras
# 		datasource = ogr.Open(dsname, 0)
# 		layer = datasource.GetLayerByName(layername)
# 		layername = layer.GetName()
# 		rasname = layername + r".tif"
# 		raspath = os.path.join(rasdir, rasname)
# 		driver = gdal.GetDriverByName("GTiff")
# 		dataset = driver.Create(raspath, width, height, 1, datatype)
# 		dataset.SetGeoTransform(geot)
# 		dataset.SetProjection(proj)
# 		dataset.SetSpatialRef(srs)
# 		gdal.RasterizeLayer(dataset, [1], layer, burn_values=[1])
# 		datasource.Destroy()
# 		del dataset
# 		return raspath
	
# 	@staticmethod
# 	def ShapeFieldvalueToRasterBandValue(raspath, rasdir, dsname, layername,
# 	                                     fieldname):
# 		ras = gdal.Open(raspath)
# 		width = ras.RasterXSize
# 		height = ras.RasterYSize
# 		geot = ras.GetGeoTransform()
# 		proj = ras.GetProjection()
# 		etwsrs = ras.GetSpatialRef().ExportToWkt()
# 		datatype = ras.GetRasterBand(1).DataType
# 		srs = osr.SpatialReference()
# 		srs.ImportFromWkt(etwsrs)
# 		del ras
# 		datasource = ogr.Open(dsname, 0)
# 		if layername is None:
# 			layer = datasource.GetLayer()
# 			layername = layer.GetName()
# 		else:
# 			layer = datasource.GetLayer()
# 		rasname = layername + r".tif"
# 		raspath = os.path.join(rasdir, rasname)
# 		driver = gdal.GetDriverByName("GTiff")
# 		if fieldname is None:
# 			dataset = driver.Create(raspath, width, height, 1, datatype)
# 		else:
# 			dataset = driver.Create(raspath, width, height, 1, gdal.GDT_Float32)
# 		dataset.SetGeoTransform(geot)
# 		dataset.SetProjection(proj)
# 		dataset.SetSpatialRef(srs)
# 		if fieldname is None:
# 			gdal.RasterizeLayer(dataset, [1], layer, burn_values=[1])
# 		else:
# 			gdal.RasterizeLayer(
# 				dataset, [1], layer, options=["ATTRIBUTE=%s" % fieldname])
# 		datasource.Destroy()
# 		del dataset
# 		return raspath

# 	def ShpToRas(self, dsname, layername, dsdir, raspath, rasdir):
# 		"""矢量文件转栅格文件，坐标可以不一致！"""
# 		ras = gdal.Open(raspath)
# 		rassrsw = ras.GetSpatialRef().ExportToWkt()
# 		del ras
# 		print(rassrsw)
# 		[dstdsname, dstlayername] = self.ShpToSRSGeomShp(
# 			dsname, layername, dsdir, dstsrs=rassrsw)
# 		newraspath = self.ShapeToRaster(
# 			raspath, dstdsname, rasdir, layername=dstlayername)
# 		shutil.rmtree(dstdsname)
# 		return newraspath
	
# 	@staticmethod
# 	def FieldToLayer(dsname, layername, fieldname, threshold,
# 	                 relationship="<="):
# 		"""获取赛选到的图层矢量数据"""
# 		datasource = ogr.Open(dsname, 1)
# 		if datasource.GetLayerByName(fieldname) is not None:
# 			datasource.DeleteLayer(fieldname)
# 		if layername is None:
# 			layer = datasource.GetLayer()
# 			layername = layer.GetName()
# 		else:
# 			layer = datasource.GetLayerByName(layername)
# 		if isinstance(threshold, str):
# 			resultslayer = datasource.ExecuteSQL(
# 				"select * from %s where %s %s'%s'" %
# 				(layername, fieldname, relationship, threshold))
# 			datasource.CopyLayer(resultslayer, fieldname)
# 			datasource.ReleaseResultSet(resultslayer)
# 			datasource.Destroy()
# 		else:
# 			select = "%s %s %f" % (fieldname, relationship, threshold)
# 			layer.SetAttributeFilter(select)
# 			datasource.CopyLayer(layer, fieldname)
# 			layer.SetAttributeFilter(None)
# 			datasource.Destroy()
# 		return [dsname, fieldname]
	
# 	@staticmethod
# 	def CopyLayer(dsname, layername, rdsname, rlayername):
# 		"""复制图层"""
# 		gdal.SetConfigOption("GDAL_FILENAME_IS_UTF8", "YES")
# 		gdal.SetConfigOption("SHAPE_ENCODING", "GBK")
		
# 		dataset = ogr.Open(dsname)
# 		if not slayername:
# 			layer = dataset.GetLayer(0)
# 		else:
# 			layer = dataset.GetLayerByName(layername)
# 		featurec = layer.GetFeatureCount()
# 		featureidxs = range(featurec)
# 		# jfeatures = [layer.GetFeature(i).ExportToJson() for i in featureidxs]
		
# 		drivername = 'ESRI Shapefile'
# 		driver = ogr.GetDriverByName(drivername)
# 		rdataset = driver.CreateDataSource(dsname)
# 		return


# class RasterPU:
# 	gdal.UseExceptions()
# 	gdal.AllRegister()
# 	driver = gdal.GetDriverByName("GTiff")
# 	wgs84srsdefn = (
# 			"GEOGCS[\"WGS 84\"," +
# 			"DATUM[\"World Geodetic System 1984\"," +
# 			"SPHEROID[\"WGS 84\",6378137,298.257223563]]," +
# 			"PRIMEM[\"Greenwich\",0]," +
# 			"UNIT[\"degree\",0.0174532925199433]," +
# 			"AXIS[\"Longitude\",EAST],AXIS[\"Latitude\",NORTH]]")
# 	datatype = gdal.GDT_UInt16
	
# 	def __init__(self):
# 		pass
	
# 	@staticmethod
# 	def GetSrsw(raspath):
# 		"""获取栅格坐标系对象，并转为字符串返回"""
# 		ras = gdal.Open(raspath, 0)
# 		srs = ras.GetSpatialRef()
# 		srsw = srs.ExportToWkt()
# 		del ras
# 		return srsw
	
# 	@staticmethod
# 	def GetGeoTransform(raspath):
# 		"""获取栅格仿射参数，并返回元组"""
# 		ras = gdal.Open(raspath, 0)
# 		geot = ras.GetGeoTransform()
# 		del ras
# 		return geot
	
# 	@staticmethod
# 	def GetProjection(raspath):
# 		"""获取栅格投影信息，并返回字符串"""
# 		ras = gdal.Open(raspath, 0)
# 		proj = ras.GetProjection()
# 		del ras
# 		return proj
	
# 	@staticmethod
# 	def GetShape(raspath):
# 		"""获取栅格形状信息，并返回列表"""
# 		ras = gdal.Open(raspath, 0)
# 		width, height, bandc = ras.RasterXSize, ras.RasterYSize, ras.RasterCount
# 		shape = [width, height, bandc]
# 		del ras
# 		return shape
	
# 	@staticmethod
# 	def GetDriverName(raspath):
# 		"""获取栅格驱动名称信息，并返字符串"""
# 		ras = gdal.Open(raspath, 0)
# 		driver = ras.GetDriver()
# 		drivername = driver.ShortName
# 		del ras
# 		return drivername
	
# 	@staticmethod
# 	def GetDataType(raspath):
# 		"""获取栅格波段数据类型，并返GDAL数据类型对象"""
# 		ras = gdal.Open(raspath, 0)
# 		driver = ras.GetDriver()
# 		datatype = ras.GetRasterBand(1).DataType
# 		del ras
# 		return datatype
	
# 	@staticmethod
# 	def GetNoDataValue(raspath):
# 		"""
# 		获取栅格波段指定空值，并返具体数值或None
# 		:param raspath:
# 		:return:
# 		"""
# 		ras = gdal.Open(raspath, 0)
# 		driver = ras.GetDriver()
# 		novalue = ras.GetRasterBand(1).GetNoDataValue()
# 		del ras
# 		return novalue
	
# 	@staticmethod
# 	def GetParams(raspath):
# 		"""获取栅格参数"""
# 		ras = gdal.Open(raspath)
# 		shape = [ras.RasterXSize, ras.RasterYSize, ras.RasterCount]
# 		geot = ras.GetGeoTransform()
# 		proj = ras.GetProjection()
# 		srsw = ras.GetSpatialRef().ExportToWkt()
# 		datatype = ras.GetRasterBand(1).DataType
# 		novalue = ras.GetRasterBand(1).GetNoDataValue()
# 		del ras
# 		return [shape, datatype, novalue, srsw, geot, proj]
	
# 	@staticmethod
# 	def RasterToArr2ds(raspath):
# 		"""获取栅格二维数组列表"""
# 		ras = gdal.Open(raspath)
# 		geot = ras.GetGeoTransform()
# 		width, height, bandc = ras.RasterXSize, ras.RasterYSize, ras.RasterCount
# 		arr2ds = [
# 			ras.GetRasterBand(i).ReadAsArray(0, 0, width, height)
# 			for i in range(1, bandc + 1)]
# 		del ras
# 		return arr2ds
	
# 	@staticmethod
# 	def RasterToArr3d(raspath):
# 		"""获得栅格的三维数组数据"""
# 		ras = gdal.Open(raspath)
# 		geot = ras.GetGeoTransform()
# 		width, height, bandc = ras.RasterXSize, ras.RasterYSize, ras.RasterCount
# 		bandid = range(1, bandc + 1)
# 		arr2ds = [
# 			ras.GetRasterBand(i).ReadAsArray(0, 0, width, height) for i in
# 			bandid]
# 		del ras
# 		arr3d = np.array(arr2ds)
# 		return arr3d
	
# 	@staticmethod
# 	def ArrsGdalDataType(arr):
# 		"""依据数组的数据类型获得相应的gdal数据类型"""
# 		if arr.dtype == r"float32":
# 			datatype = gdal.GDT_Float32
# 		elif arr.dtype == r"uint8":
# 			datatype = gdal.GDT_Byte
# 		elif arr.dtype == r"uint16":
# 			datatype = gdal.GDT_UInt16
# 		elif arr.dtype == r"uint32":
# 			datatype = gdal.GDT_UInt32
# 		elif arr.dtype == r"int32":
# 			datatype = gdal.GDT_Int32
# 		elif arr.dtype == r"int16":
# 			datatype = gdal.GDT_Int16
# 		else:
# 			datatype = gdal.GDT_Unknown
# 		return datatype
	
# 	@staticmethod
# 	def GetRasAttrbutes(raspath):
# 		"""获取栅格的属性信息"""
# 		ras = gdal.Open(raspath)
# 		drivername = ras.GetDriver().ShortName
# 		width, height, bandc = ras.RasterXSize, ras.RasterYSize, ras.RasterCount
# 		shape = [width, height]
# 		geot = ras.GetGeoTransform()
# 		proj = ras.GetProjection()
# 		srsw = ras.GetSpatialRef().ExportToWkt()
# 		datatype = ras.GetRasterBand(1).DataType
# 		novalue = ras.GetRasterBand(1).GetNoDataValue()
# 		del ras
# 		return [drivername, shape, datatype, srsw, geot, proj, novalue]
	
# 	@staticmethod
# 	def PointPCtoSC(geot, pixelpoint):
# 		"""根据栅格仿射参数计算像素点的空间坐标"""
# 		(left, xpixelsize, yangle, top, xangle, ypixelsize) = geot
# 		[xpixeldistance, ypixeldistance] = pixelpoint
# 		pointx = left + xpixelsize * xpixeldistance + ypixeldistance * yangle
# 		pointy = top + ypixeldistance * ypixelsize + xpixeldistance * xangle
# 		spacepoint = [pointx, pointy]
# 		return spacepoint
	
# 	@staticmethod
# 	def PointSCtoPC(geot, spacepoint):
# 		"""根据栅格仿射参数计算空间点的像素坐标"""
# 		(left, xpixelsize, yangle, top, xangle, ypixelsize) = geot
# 		[xspacedistance, yspacedistance] = spacepoint
# 		pointx = (xspacedistance - left) / xpixelsize
# 		pointy = (yspacedistance - top) / ypixelsize
# 		pixelpoint = [pointx, pointy]
# 		return pixelpoint
	
# 	@classmethod
# 	def CreateRaster(cls, params, arrs):
# 		"""创建tif格式的栅格文件"""
# 		[rasdir, sign, shape, datatype, novalue, srsw, geot, proj] = params
# 		rasname = sign + ".tif"
# 		raspath = os.path.join(rasdir, rasname)
# 		driver = gdal.GetDriverByName("GTiff")
# 		width, height, bandc = shape
# 		ras = driver.Create(raspath, width, height, bandc, datatype)
# 		ras.SetGeoTransform(geot)
# 		srs = osr.SpatialReference()
# 		srs.ImportFromWkt(srsw)
# 		ras.SetSpatialRef(srs)
# 		bandids = range(1, bandc + 1)
# 		for bandid in bandids:
# 			band = ras.GetRasterBand(bandid)
# 			band.WriteArray(arrs[bandid - 1])
# 			if novalue is not None:
# 				band.SetNoDataValue(novalue)
# 		return
	
# 	@classmethod
# 	def RightBottomExpand(cls, raspath, rasdir, expend):
# 		"""右下扩展栅格影像"""
# 		[shape, datatype, novalue, srsw, geot, proj] = cls.GetParams(raspath)
# 		[width, height, bandc] = shape
# 		[right, bottom] = expend
# 		shape = [width + right, height + bottom, bandc]
# 		rasname = os.path.split(raspath)[1]
# 		name = os.path.splitext(rasname)[0]
# 		sign = name + "_Expand"
# 		params = [rasdir, sign] + [shape, datatype, novalue, srsw, geot, proj]
# 		arrs = cls.RasterToArr2ds(raspath)
# 		cls.CreateRaster(params, arrs)
# 		return
	
# 	@classmethod
# 	def ArrsToRaster(
# 			cls, arrs, folder, sign, shape, geot, proj, datatype=None,
# 			srswkt=None, novalue=None, drivername=None, fileextend=None):
# 		if drivername is None:
# 			raspath = os.path.join(folder, sign + r".tif")
# 			driver = cls.driver
# 		else:
# 			raspath = os.path.join(folder, sign + fileextend)
# 			driver = gdal.GetDriverByName(drivername)
# 		if os.path.exists(raspath):
# 			print(raspath, ":该影像存在，退出合成！")
# 			return raspath
# 		bandc = len(arrs)
# 		[width, height] = shape
# 		if datatype is None:
# 			datatype = cls.datatype
# 		dataset = driver.Create(raspath, width, height, bandc, datatype, [])
# 		dataset.SetGeoTransform(geot)
# 		if srswkt is None:
# 			srswkt = osr.SpatialReference(wkt=cls.wgs84srsdefn)
# 			dataset.SetSpatialRef(srswkt)
# 		else:
# 			srswkt = osr.SpatialReference(wkt=srswkt)
# 			dataset.SetSpatialRef(srswkt)
# 		dataset.SetProjection(proj)
# 		for i in range(bandc):
# 			band = dataset.GetRasterBand(i + 1)
# 			band.WriteArray(arrs[i])
# 			if novalue is not None:
# 				band.SetNoDataValue(novalue)
# 		del dataset
# 		return raspath
	
# 	@classmethod
# 	def RasterToJPG(cls, rasfile, jpgdir):
# 		"""栅格转jpg文件"""
# 		arrs = cls.RasterToArr2ds(rasfile)
# 		rassign = os.path.splitext(os.path.split(rasfile)[1])[0]
# 		jpgfile = os.path.join(jpgdir, rassign + r".jpg")
# 		arrtmp = [arr.astype(np.uint8) for arr in arrs]
# 		img = cv2.merge([arrtmp[2], arrtmp[1], arrtmp[0]])  # 转为图像格式(b，g，r)
# 		cv2.imwrite(jpgfile, img)
# 		return jpgfile
	
# 	@classmethod
# 	def GetNewGeoTansform(cls, geot, point):
# 		"""根据原仿射信息与左上角坐标构建仿射参数"""
# 		[newgeot0, newgeot3] = cls.PointPCtoSC(geot, point)
# 		newgeot1, newgeot2 = geot[1], geot[2]
# 		newgeot4, newgeot5 = geot[4], geot[5]
# 		newgeot = (newgeot0, newgeot1, newgeot2, newgeot3, newgeot4, newgeot5)
# 		return newgeot
	
# 	@classmethod
# 	def ClipRasToArrs(cls, rasfile, xoff, yoff, xsize, ysize):
# 		"""获取窗口区域波段的数组列表，如果超出边界会自动修改窗口大小！"""
# 		ras = gdal.Open(rasfile)
# 		width, height = ras.RasterXSize, ras.RasterYSize
# 		bandc = ras.RasterCount
# 		if xoff + xsize > width:
# 			xsize = width - xoff
# 		if yoff + ysize > height:
# 			ysize = height - yoff
# 		bandi = range(1, bandc + 1)
# 		arr2ds = [
# 			ras.GetRasterBand(i).ReadAsArray(xoff, yoff, xsize, ysize) for i in
# 			bandi]
# 		del ras
# 		return arr2ds
	
# 	@classmethod
# 	def BuildRaster(cls, rasdir, name, geot, srsw, proj, arrs, datatype,
# 	                novalue):
# 		"""构建栅格文件, 依据数组形状和数据类型创建影像"""
# 		(height, width) = arrs[0].shape
# 		bandc = len(arrs)
# 		rasfile = os.path.join(rasdir, name)
# 		if os.path.exists(rasfile):
# 			print(rasfile, "栅格文件存在，跳过！")
# 			return rasfile
# 		driver = gdal.GetDriverByName("GTiff")
# 		dataset = driver.Create(rasfile, width, height, bandc, datatype)
# 		dataset.SetGeoTransform(geot)
# 		srs = osr.SpatialReference(srsw)
# 		dataset.SetSpatialRef(srs)
# 		dataset.SetProjection(proj)
# 		[dataset.GetRasterBand(i + 1).WriteArray(arrs[i]) for i in range(bandc)]
# 		if novalue is not None:
# 			[dataset.GetRasterBand(i + 1).SetNoDataValue(novalue) for i in
# 			 range(bandc)]
# 		del dataset
# 		return rasfile
	
# 	@classmethod
# 	def ClipRaster(cls, rasfile, rasdir, winsize):
# 		"""裁剪栅格至指定目录中, 若超出边界，窗口会自适应剩余大小"""
# 		[xsize, ysize] = winsize
# 		[shape, datatype, novalue, srsw, geot, proj] = cls.GetParams(rasfile)
# 		rasname = os.path.split(rasfile)[1]
# 		sign = os.path.splitext(rasname)[0]
# 		rasfolder = os.path.join(rasdir, sign + r"_Clip")
# 		if os.path.exists(rasfolder):
# 			print("正在更新裁剪结果文件夹！")
# 		# shutil.rmtree(rasfolder)
# 		# os.makedirs(rasfolder)
# 		else:
# 			os.makedirs(rasfolder)
# 		[width, height] = shape[:-1]
# 		xclipc, yclipc = math.ceil(width / xsize), math.ceil(height / ysize)
# 		clips = [
# 			[xindex, yindex] for yindex in range(yclipc) for xindex in
# 			range(xclipc)]
# 		print("Start Cliping Raster:\n", rasfile)
# 		print("Generate Folder:\n", rasfolder)
# 		for index in tqdm(range(len(clips))):
# 			clipitem = clips[index]
# 			[xindex, yindex] = clipitem
# 			xoff, yoff = xindex * xsize, yindex * ysize
# 			clipid = "0" * (7 - len(str(index))) + str(index)
# 			name = "%s_%s_%s_%s.tif" % (clipid, sign, str(xindex), str(yindex))
# 			arrs = cls.ClipRasToArrs(rasfile, xoff, yoff, xsize, ysize)
# 			newgeot = cls.GetNewGeoTansform(geot, [xoff, yoff])
# 			file = cls.BuildRaster(
# 				rasfolder, name, newgeot, srsw, proj, arrs, datatype, novalue)
# 		print(rasfile, "\n Cliping Raster End!")
# 		return rasfolder
	
# 	@staticmethod
# 	def GetHeightPrecisionRaterAttribute(raspaths):
# 		"""在多个raster中获得最高精度raster的相关attribute"""
# 		for raspath in raspaths:
# 			ras = gdal.Open(raspath)
# 			pres.append(abs(ras.GetGeoTransform()[1]))
# 			del ras
# 		standardindex = pres.index(min(pres))
# 		ras = gdal.Open(raspaths[standardindex])
# 		shape = [ras.RasterXSize, ras.RasterYSize]
# 		geot = ras.GetGeoTransform()
# 		srs = ras.GetSpatialRef().ExportToWkt()
# 		proj = ras.GetProjectionRef()
# 		datatype = ras.GetRasterBand(1).DataType
# 		del ras
# 		return [shape, geot, srs, proj, datatype]
	
# 	@staticmethod
# 	def GetRasterFrameETJGeometry(raspath):
# 		"""获取栅格影像边框几何对象的json形式"""
# 		ras = gdal.Open(raspath)
# 		width, heigth = ras.RasterXSize, ras.RasterYSize
# 		srsw = ras.GetSpatialRef().ExportToWkt()
# 		geot = ras.GetGeoTransform()
# 		frame = [
# 			[geot[0], geot[3]],
# 			[geot[0], geot[3] + height * geot[5]],
# 			[geot[0] + width * geot[1], geot[3] + height * geot[5]],
# 			[geot[0] + width * geot[1], geot[3]]]
# 		[ring.AddPoint(point[0], point[1]) for point in frame]
# 		ring.CloseRings()
# 		polygon = ogr.Geometry(ogr.wkbPolygon)
# 		polygon.AddGeometry(ring)
# 		etjgeometry = polygon.ExportToJson()
# 		del ras
# 		return etjgeometry


# S3PU = Sqlite3PU()
# RPU = RasterPU()
# SPU = ShapePU()


# def ClassToFuncthion(params):
# 	"""把类对象和方法转换为普通函数"""
# 	[goalobject, args] = params
# 	goalobject.Start(args)
# 	return


class UniversalTool:
	
	def __init__(self):
		"""
		通用工具
		"""
		pass

	@staticmethod
	def ShpToFeatureGeometryDictList(datasourcename, layername=None):
		"""
		获得矢量文件所有json格式要素geometry列表
		:param datasourcename: shp文件路径
		:param layername: 图层名称
		:return: 所有要素属性字典列表
		"""
		gdal.SetConfigOption("SHAPE_ENCODING", "UTF-8")
		datasource = ogr.Open(datasourcename)
		if layername == 0 or layername is None:
			layer = datasource.GetLayer(0)
		else:
			layer = datasource.GetLayerByName(layername)
		featurecount = layer.GetFeatureCount()
		featuregeometrydictlist = []
		for featureindex in range(featurecount):
			feature = layer.GetFeature(featureindex)
			geometry = feature.geometry()
			geometryjson = geometry.ExportToJson()
			geometrydict = json.loads(geometryjson)
			featuregeometrydictlist.append(geometrydict)
			feature.Destroy()
		datasource.Destroy()
		return featuregeometrydictlist

	@staticmethod
	def ShpToFeatureFieldDictList(datasourcename, layername=None):
		"""
		获取shp文件字段字典列表
		:param datasourcename: shp文件路径
		:param layername: 图层名称
		:return: 所有要素字段字典列表
		"""
		gdal.SetConfigOption("SHAPE_ENCODING", "UTF-8")
		datasource = ogr.Open(datasourcename)
		if layername == 0 or layername is None:
			layer = datasource.GetLayer(0)
		else:
			layer = datasource.GetLayerByName(layername)
		featurecount = layer.GetFeatureCount()
		featurefielddictlist = []
		for featureindex in range(featurecount):
			feature = layer.GetFeature(featureindex)
			fielddict = feature.items()
			featurefielddictlist.append(fielddict)
			feature.Destroy()
		datasource.Destroy()
		return featurefielddictlist

	@staticmethod
	def ShpToFeatureDictList(datasourcename, layername=None):
		"""
		获取shp文件指定图层所有要素的属性与几何的字典列表
		:param datasourcename: shp文件路径
		:param layername: 图层名称
		:return: 要素属性与几何字典的列表
		"""
		gdal.SetConfigOption("SHAPE_ENCODING", "UTF-8")
		datasource = ogr.Open(datasourcename)
		if layername == 0 or layername is None:
			layer = datasource.GetLayer(0)
		else:
			layer = datasource.GetLayerByName(layername)
		featurecount = layer.GetFeatureCount()
		featuredictlist = []
		for featureindex in tqdm(range(featurecount)):
			feature = layer.GetFeature(featureindex)
			featurejson = feature.ExportToJson()
			featuredict = json.loads(featurejson)
			featuredictlist.append(featuredict)
			feature.Destroy()
		datasource.Destroy()
		return featuredictlist

	@staticmethod
	def GeometryDictListTransfSrs(geometrydictlist, insrsw, outsrsw):
		"""
		转换所有几何字典列表坐标系
		:param geometrydictlist: 需要转换的几何字典列表
		:param insrsw: 几何字典列表中坐标点所在的坐标系wkt字符串格式
		:param outsrsw: 需要转换到的目标坐标系的wkt字符串格式
		:return: 转换后的几何字典列表
		"""
		insrs = osr.SpatialReference(wkt=insrsw)
		outsrs = osr.SpatialReference(wkt=outsrsw)
		ct = osr.CreateCoordinateTransformation(insrs, outsrs)
		outgeometrydictlist = []
		for geometrydict in geometrydictlist:
			geometrytype = geometrydict["type"]
			if geometrytype == "Polygon":
				polygon = geometrydict["coordinates"]
				outpolygon = [[
					list(ct.TransformPoint(point[1], point[0]))[:2]
					for point in ring]
					for ring in polygon]
				geometrydict["coordinates"] = outpolygon
				outgeometrydictlist.append(geometrydict)
			elif geometrytype == "MultiPolygon":
				multipolygon = geometrydict["coordinates"]
				outmultipolygon = [[[
						list(ct.TransformPoint(point[1], point[0]))[:2]
						for point in ring]
						for ring in polygon]
						for polygon in multipolygon]
				geometrydict["coordinates"] = outmultipolygon
				outgeometrydictlist.append(geometrydict)
			else:
				print("非多边形几何体，转换出错！")
				pass
		return outgeometrydictlist

	@staticmethod
	def CreateEmptyShp(datasourcename, layername, srsw, geomtype, fields):
		"""
        创建新的空shp文件及图层
        :param fields:
        :param datasourcename: shp文件路径
        :param layername: 图层名称
        :param srsw: wkt字符串格式的坐标系
        :param geomtype: 图层要素几何类型
        :return:
        """
		gdal.SetConfigOption("GDAL_FILENAME_IS_UTF8", "YES")
		drivername = "ESRI Shapefile"
		driver = ogr.GetDriverByName(drivername)
		datasource = driver.CreateDataSource(datasourcename)
		srs = osr.SpatialReference(wkt=srsw)
		layer = datasource.CreateLayer(layername, srs, geomtype)
		layer.CreateFields(fields)
		datasource.Destroy()
		return

	@staticmethod
	def CreateEmptyShpFromFieldDictList(shapefilepath, layername, srsw, geomtype, fielddictlist):
		"""
		依据字段定义字典列表创建空的shp文件
		:param shapefilepath: shp文件路径
		:param layername: 图层名称
		:param srsw: 参考系
		:param geomtype: 几何类型
		:param fielddictlist: 字段字典列表
		:return:
		"""
		gdal.SetConfigOption("GDAL_FILENAME_IS_UTF8", "YES")
		driver = ogr.GetDriverByName("ESRI Shapefile")
		datasource = driver.CreateDataSource(shapefilepath)
		srs = osr.SpatialReference(wkt=srsw)
		layer = datasource.CreateLayer(layername, srs, geomtype)
		for fielddict in fielddictlist:
			fielddefn = ogr.FieldDefn()
			fielddefn.name = fielddict["name"]
			fielddefn.type = fielddict["type"]
			fielddefn.width = fielddict["width"]
			fielddefn.precision = fielddict["precision"]
			fielddefn.justify = fielddict["justify"]
			layer.CreateField(fielddefn)
			fielddefn.Destroy()
		datasource.Destroy()
		return

	@staticmethod
	def FeatureDictListUpdataShp(featuredictlist, datasourcename, layername=None):
		"""
		依据要素字典列表更新shp文件指定图层
		:param featuredictlist: 要素字典列表
		:param datasourcename: shp文件路径
		:param layername: 图层名称
		:return:
		"""
		gdal.SetConfigOption("SHAPE_ENCODING", "GBK")
		datasource = ogr.Open(datasourcename, 1)
		if layername == 0 or layername is None:
			layer = datasource.GetLayer(0)
		else:
			layer = datasource.GetLayerByName(layername)
		featuredf = layer.GetLayerDefn()
		for featuredict in featuredictlist:
			propertydict = featuredict["properties"]
			feature = ogr.Feature(featuredf)
			for key in propertydict:
				value = propertydict[key]
				# print(key, value)
				feature.SetField2(key, value)
			geometrydict = featuredict["geometry"]
			geometryjson = json.dumps(geometrydict)
			geometry = ogr.CreateGeometryFromJson(geometryjson)
			feature.SetGeometry(geometry)
			layer.CreateFeature(feature)
			feature.Destroy()
		datasource.Destroy()
		return

	@classmethod
	def MultipleShpFilesMerge(cls, shpfilepathlist, newshppath, newlayername):
		"""
		多个shp文件的默认图层，前提是属性一致，合成一个shp文件
		:param shpfilepathlist: 原始shp文件路劲列表
		:param newshppath: 生成的shp文件路径
		:param newlayername: 生成的shp文件图层名称
		:return:
		"""
		gdal.SetConfigOption("SHAPE_ENCODING", "UTF-8")
		firstshpfilepath = shpfilepathlist[0]
		datasource = ogr.Open(firstshpfilepath)
		layer = datasource.GetLayer(0)
		srs = layer.GetSpatialRef()
		srsw = srs.ExportToWkt()
		geomtype = layer.GetGeomType()
		fields = layer.schema
		cls.CreateEmptyShp(newshppath, newlayername, srsw, geomtype, fields)
		for shppath in shpfilepathlist:
			featuredictlist = cls.ShpToFeatureDictList(shppath)
			cls.FeatureDictListUpdataShp(featuredictlist, newshppath, layername=newlayername)
		datasource.Destroy()
		return

	@classmethod
	def ShpTransformSrs(cls, dsname, layername, srsw, savedir):
		"""
		依据输入坐标字符串修改shp文件目标图层的坐标系
		:param dsname: shp文件夹
		:param layername:目标图层可以为0或者None，但必须指定参数
		:param srsw: 空间坐标系wkt字符串格式
		:param savedir: 新shp文件保存路径，切记不能与原始shp文件同文件夹
		:return:
		"""
		srs = osr.SpatialReference(wkt=srsw)
		datasource = ogr.Open(dsname)
		if layername == 0 or layername is None:
			layer = datasource.GetLayer(0)
			layername = layer.GetName()
		else:
			layer = datasource.GetLayerByName(layername)
		layersrs = layer.GetSpatialRef()
		srsname, lysrsname = srs.GetName(), layersrs.GetName()
		if srsname == lysrsname:
			print("栅格与矢量坐标系一致，无需转换！")
			return [dsname, layername]
		layersrsw = layersrs.ExportToWkt()
		geomtype = layer.GetGeomType()
		fields = layer.schema
		outdsname = os.path.join(savedir, os.path.split(dsname)[1])
		cls.CreateEmptyShp(outdsname, layername, srsw, geomtype, fields)
		featuredictlist = cls.ShpToFeatureDictList(dsname, layername)
		geometrydictlist = [featuredict["geometry"] for featuredict in featuredictlist]
		outgeometrydictlist = cls.GeometryDictListTransfSrs(geometrydictlist, layersrsw, srsw)
		outfeaturedictlist = []
		for featuredict, geometrydict in zip(featuredictlist, outgeometrydictlist):
			featuredict["geometry"] = geometrydict
			outfeaturedictlist.append(featuredict)
		cls.FeatureDictListUpdataShp(outfeaturedictlist, outdsname, layername)
		datasource.Destroy()
		return [outdsname, layername]

	@staticmethod
	def ShpLayerIntersectToJson(dsname1, layername1, dsname2, layername2, jsonpath):
		"""

		:param dsname1:
		:param layername1:
		:param dsname2:
		:param layername2:
		:param jsonpath:
		:return:
		"""
		datasource1 = ogr.Open(dsname1)
		if layername1 == 0 or layername1 is None:
			layer1 = datasource1.GetLayer(0)
		else:
			layer1 = datasource1.GetLayerByName(layername1)
		datasource2 = ogr.Open(dsname2)
		if layername2 == 0 or layername2 is None:
			layer2 = datasource2.GetLayer(0)
		else:
			layer2 = datasource2.GetLayerByName(layernaem2)
		featurecount1 = layer1.GetFeatureCount()
		featurecount2 = layer2.GetFeatureCount()
		fielddictlist = []
		for featureindex1 in range(featurecount1):
			feature1 = layer1.GetFeature(featureindex1)
			geometry1 = feature1.geometry()
			for featureindex2 in range(featurecount2):
				feature2 = layer2.GetFeature(featureindex2)
				geometry2 = feature2.geometry()
				if geometry1.Intersect(geometry2):
					feature1fielddict = feature1.items()
					feature2fielddict = feature2.items()
					fielddict = dict(feature1fielddict, **feature2fielddict)
					fielddictlist.append(fielddict)
		with open(jsonpath, 'w', encoding="utf-8") as jsonfile:
			json.dump(fielddictlist, jsonfile, ensure_ascii=False, indent=4)
		datasource1.Destroy()
		datasource2.Destroy()
		return

	@staticmethod
	def SelectFieldRangeToFeatureDictList(shapefilepath, layername, fieldname, valuerange):
		"""
		依据指定字段的值域筛选要素为字典列表
		:param shapefilepath: shp文件路径
		:param layername: 图层名称
		:param fieldname: 字段名称
		:param valuerange: 值域
		:return:
		"""
		gdal.SetConfigOption("SHAPE_ENCODING", "UTF-8")
		[minvalue, maxvalue] = valuerange
		datasource = ogr.Open(shapefilepath)
		if layername == 0 or layername is None:
			layer = datasource.GetLayer(0)
		else:
			layer = datasource.GetLayerByName(layername)
		featurecount = layer.GetFeatureCount()
		featuredictlist = []
		for featureindex in range(featurecount):
			feature = layer.GetFeature(featureindex)
			fieldindex = feature.GetFieldIndex(fieldname)
			fieldvalue = feature.GetField(fieldindex)
			if minvalue is None and maxvalue is not None:
				if fieldvalue <= maxvalue:
					featurejson = feature.ExportToJson()
					featuredict = json.loads(featurejson)
					featuredictlist.append(featuredict)
					# feature.Destroy()
			elif minvalue is not None and maxvalue is None:
				if fieldvalue >= minvalue:
					featurejson = feature.ExportToJson()
					featuredict = json.loads(featurejson)
					featuredictlist.append(featuredict)
					# feature.Destroy()
			elif minvalue is not None and maxvalue is not None:
				if minvalue <= fieldvalue <= maxvalue:
					featurejson = feature.ExportToJson()
					featuredict = json.loads(featurejson)
					featuredictlist.append(featuredict)
					# feature.Destroy()
			else:
				feature.Destroy()
		return featuredictlist

	@staticmethod
	def GetShpFileDefn(shapefilepath, layername=None):
		"""
		从一个存在的shp文件中得到创建一个shape文件的必要参数
		:param shapefilepath: shp文件路径
		:param layername: 图层名称
		:return:
		"""
		datasource = ogr.Open(shapefilepath)
		if layername == 0 or layername is None:
			layer = datasource.GetLayer(0)
		else:
			layer = datasource.GetLayerByName(layername)
		fieldlist = layer.schema
		fielddictlist = []
		for field in fieldlist:
			fielddict = {
				"name": field.name,
				"type": field.type,
				"width": field.width,
				"justify": field.justify,
				"precision": field.precision}
			fielddictlist.append(fielddict)
		geomtype = layer.GetGeomType()
		srs = layer.GetSpatialRef()
		srsw = srs.ExportToWkt()
		datasource.Destroy()
		return [srsw, geomtype, fielddictlist]

	@classmethod
	def SqlSelectFieldAsShp(cls, dsname, lyname, fieldname, valuerange, dstdsname, dstlyname):
		"""
		根据某一字段的值域创建新的shp文件
		:param dsname: 原始shp文件路径
		:param lyname: 原始layer名称
		:param fieldname: 字段名称
		:param valuerange: 值域
		:param dstdsname: 新shp文件路径
		:param dstlyname: 新图层名称
		:return:
		"""
		featuredictlist = cls.SelectFieldRangeToFeatureDictList(dsname, lyname, fieldname, valuerange)
		[srsw, geomtype, fielddictlist] = cls.GetShpFileDefn(dsname, lyname)
		cls.CreateEmptyShpFromFieldDictList(dstdsname, dstlyname, srsw, geomtype, fielddictlist)
		cls.FeatureDictListUpdataShp(featuredictlist, dstdsname, dstlyname)
		return

	@staticmethod
	def GetSubFile(pardir):
		"""
		获取该文件夹下所有子文件路径
		"""
		names = os.listdir(pardir)
		subfiles = []
		for name in names:
			unkownpath = os.path.join(pardir, name)
			if os.path.isfile(unkownpath):
				subfiles.append(unkownpath)
		return subfiles
	
	@staticmethod
	def GetSubDir(pardir):
		"""获得所有子目录完整路径"""
		names = os.listdir(pardir)
		subdirs = []
		for name in names:
			unkownpath = os.path.join(pardir, name)
			if os.path.isdir(unkownpath):
				subdirs.append(unkownpath)
		return subdirs

	@classmethod
	def LayerNamrCnToEn(cls, dsname, lyname):
		"""保证图层名一定不含中文字符"""
		ds = ogr.Open(dsname)
		if not lyname:
			ly = ds.GetLayer(0)
		else:
			ly = ds.GetLayerByName(lyname)
		lyname = ly.GetName()
		pylyname = cls.HanziToPinyin(lyname)
		if pylyname != lyname:
			drivername = 'ESRI Shapefile'
			gdal.SetConfigOption("GDAL_FILENAME_IS_UTF8", "YES")
			gdal.SetConfigOption("SHAPE_ENCODING", "GBK")
			driver = ogr.GetDriverByName(drivername)
			shpdir, dssign = os.path.split(dsname)
			rdsname = os.path.join(shpdir, dssign+"_PY")
			if os.path.exists(rdsname):
				shutil.rmtree(rdsname)
			rds = driver.CreateDataSource(rdsname)
			rds.CopyLayer(ly, pylyname)
			rds.Destroy()
			ds.Destroy()
			return [rdsname, pylyname]
		ds.Destroy()
		return [dsname, lyname]
	
	@classmethod
	def GetNewGeoTansform(cls, geot, point):
		"""根据原仿射信息与左上角坐标构建仿射参数"""
		[newgeot0, newgeot3] = cls.PointPCtoSC(geot, point)
		newgeot1, newgeot2 = geot[1], geot[2]
		newgeot4, newgeot5 = geot[4], geot[5]
		newgeot = (newgeot0, newgeot1, newgeot2, newgeot3, newgeot4, newgeot5)
		return newgeot
	
	@classmethod
	def Getarea(cls, polygon):
		"""
		给出任意一个多边形，其顶点坐标依次为（x0，y0），（x1，y1）
		，（x2，y2），...，（xn，yn）（其中n=2，3，4，…），则其
		面积可表示为：
		"""
		n = len(polygon)
		if n < 3:
			return 0
		area = 0
		for i in range(n - 2):
			# 以第一个坐标点为原点，将多边形分割为n-2个三角形，
			# 分别计算每个三角形面积后累加得多边形面积
			area += cls.CalculateTriangleArea(
				polygon[0], polygon[i + 1], polygon[i + 2])
		return abs(area)
	
	@staticmethod
	def CalculateTriangleArea(pointa, pointb, pointc):
		"""向量叉乘法计算三角形面积"""
		trianglearea = 0.5 * (
				(pointb[0] - pointa[0]) * (pointc[1] - pointa[1]) -
				(pointb[1] - pointa[1]) * (pointc[0] - pointa[0]))
		return trianglearea

	@staticmethod
	def RasterToReshapeArr2ds(raspath, shape):
		"""依据形状缩放栅格获得波段数组列表"""
		[width, height] = shape
		ras = gdal.Open(raspath)
		raswidth = ras.RasterXSize
		rasheight = ras.RasterYSize
		bandcount = ras.RasterCount
		arr2ds = [
			ras.GetRasterBand.ReadAsArray(0, 0, raswidth, rasheight)
			for index in range(1, bandcount + 1)]
		if rasheight == height and raswidth == width:
			del ras
			return arr2ds
		else:
			outarr2ds = []
			for arr2d in arr2ds:
				reshapearr = cv2.resize(
					arr2d, (width, height), 0, 0, interpolation=cv2.INTER_NEAREST)
				outarr2ds.append(reshapearr)
			del ras
			return outarr2ds
	
	@staticmethod
	def RasterReshapeByGeo(raspath, rgeo, rasdir):
		"""栅格重采样(依据新仿射信息)"""
		ras = gdal.Open(raspath)
		rasname = os.path.split(raspath)[1]
		rassign = os.path.splitext(rasname)[0]
		geot = ras.GetGeoTransform()
		proj = ras.GetProjection()
		srs = ras.GetSpatialRef()
		width, height, bandc = ras.RasterXSize, ras.RasterYSize, ras.RasterCount
		arr2ds = [
			ras.GetRasterBand(i).ReadAsArray(0, 0, width, height)
			for i in range(1, bandc + 1)]
		datatype = ras.GetRasterBand(1).DataType
		novalue = ras.GetRasterBand(1).GetNoDataValue()
		del ras
		size, fx, fy = (0, 0), geot[1] / rgeo[1], geot[5] / rgeo[5]
		rarr2ds = [
			cv2.resize(arr2d, size, fx=fx, fy=fy, interpolation=cv2.INTER_NEAREST)
			for arr2d in arr2ds]
		rwidth, rheight = int(fx * width), int(fy * height)
		rraspath = os.path.join(rasdir, rassign+r".tiif")
		driver = gdal.GetDriverByName("GTiff")
		rras = driver.Create(rraspath, rwidth, rheight, bandc, datatype)
		rras.SetGeoTransform(rgeo)
		rras.SetSpatialRef(srs)
		rras.SetProjection(proj)
		for i in range(1, bandc + 1):
			band = rras.GetRasterBand(i)
			band.WriteArray(rarr2ds[i - 1])
			if novalue is not None:
				band.SetNoDataValue(novalue)
			del band
		del rras
		return rraspath
	
	@staticmethod
	def RasterReshapeByShp(raspath, shape, rasdir):
		"""栅格重采样,未完成"""
		ras = gdal.Open(raspath)
		width, height, bandc = ras.RasterXSize, ras.RasterYSize, ras.RasterCount
		geot = ras.GetGeoTransform()
		proj = ras.GetProjection()
		if height == shape[1] and width == shape[0]:
			del ras
			return raspath
		arr2ds = [
			ras.GetRasterBand(i).ReadAsArray(0, 0, width, height)
			for i in range(1, bandc + 1)]
		rarr2ds = [
			cv2.resize(arr2d, (width, height), 0, 0,
			           interpolation=cv2.INTER_NEAREST)
			for arr2d in arr2ds]
		
		return
	
	@staticmethod
	def HanziToPinyin(instr):
		"""判断字符串中是否包含中文字符，若有，则用中文拼替换，没有，则返回原字符串"""
		outstrs = list(instr)
		strc = len(outstrs)
		for index in range(strc):
			if '\u4e00' <= outstrs[index] <= '\u9fff':
				hanzistr = outstrs[index]
				pinyinstrs = lazy_pinyin(hanzistr)  # 返回的是拼音列表
				pinyinstr = pinyinstrs[0]
				capitalpp = pinyinstr[0].upper() + pinyinstr[1:]
				outstrs[index] = capitalpp
		outstr = "".join(outstrs)
		return outstr
	
	@classmethod
	def GetEnglishNameFile(cls, inpath, outdir=None):
		"""检查文件名中是否包含中文字符，如果包含，修改文件名并生成相应的文件"""
		basedir, filename = os.path.split(inpath)
		name, extend = os.path.splitext(filename)
		newname = cls.HanziToPinyin(name)
		if newname == name:
			print("%s文件名不包含中文字符！" % filename)
			return inpath
		if outdir is None:
			outpath = os.path.join(basedir, newname + extend)
		else:
			outpath = os.path.join(outdir, newname + extend)
		if os.path.exists(outpath):
			print("目标文件存在退出：\n%s" % outpath)
			return outpath
		shutil.copyfile(inpath, outpath)
		return outpath
	
	@staticmethod
	def CopyDirToExistDir(sourcefolderpath, savedir):
		"""
		复制文件夹已存在的目录中
		:param sourcefolderpath:
		:param savedir:
		:return:
		"""
		foldername = os.path.split(sourcefolderpath)[1]
		newfolderpath = os.path.join(savedir, foldername)
		shutil.copytree(sourcefolderpath, newfolderpath)
		return

	@staticmethod
	def CopyFileToExistDir(sourcefilepath, savedir):
		"""
		复制文件列表中的文件到指定目录中
		:param filepath: 需要复制的文件路径列表
		:param savedir: 保存文件的目录
		:return:
		"""
		filename = os.path.split(sourcefilepath)[1]
		newfilepath = os.path.join(savedir, filename)
		shutil.copyfile(filepath, newfilepath)
		return

	@staticmethod
	def UnzipFile(zippath, unzipdir):
		"""解压文件"""
		zipfilesign = os.path.splitext(os.path.split(zippath)[1])[0]
		unzipfilepath = os.path.join(unzipdir, zipfilesign)
		if os.path.exists(unzipfilepath):
			return print(unzipfilepath, ":解压文件存在！")
		else:
			os.makedirs(unzipfilepath)
		rasterzipfile = zipfile.ZipFile(zippath, "r")
		for file in rasterzipfile.namelist():
			rasterzipfile.extract(file, unzipfilepath)
		rasterzipfile.close()
		return unzipfilepath
	
	@classmethod
	def GetGoalFile(cls, infolder, sign=None):
		"""搜索获得目标文件路径集"""
		if sign is None:
			return cls.FindAllFile(infolder)
		elif sign[0] == r".":
			filepaths = cls.FindAllFile(infolder)
			rasfilepaths = [
				filepath
				for filepath in filepaths
				if os.path.splitext(os.path.split(filepath)[1])[1] == sign]
			return rasfilepaths
		else:
			filepaths = cls.FindAllFile(infolder)
			rasfilepaths = [
				filepath
				for filepath in filepaths
				if os.path.splitext(os.path.split(filepath)[1])[0] == sign]
			return rasfilepaths
	
	@classmethod
	def FindAllFile(cls, infolder):
		"""寻找该目录下的所有文件"""
		names = os.listdir(infolder)
		filepaths = []
		for name in names:
			unkownfilefolder = os.path.join(infolder, name)
			if os.path.isfile(unkownfilefolder):
				filepaths.append(unkownfilefolder)
			elif os.path.isdir(unkownfilefolder):
				filepaths = filepaths + cls.FindAllFile(unkownfilefolder)
		return filepaths
	
	@staticmethod
	def DictToJsonFile(jsondir, jsonsign, data):
		"""字典转json文件"""
		if not os.path.exists(jsondir):
			return print("保存json文件的目录不存在！")
		jsonpath = os.path.join(jsondir, jsonsign + r".json")
		if os.path.exists(jsonpath):
			return print("json文件存在,无法创建！")
		print("Start Creating：\n%s\n......" % jsonpath)
		with open(jsonpath, 'w', encoding="utf-8") as jsonfile:
			json.dump(data, jsonfile, ensure_ascii=False, indent=4)
		print("End: \n%s" % jsonpath)
		return
	
	@staticmethod
	def JudgmentYear(year):
		"""判断该年是否是瑞年"""
		if (year % 4) == 0:
			if (year % 100) == 0:
				if (year % 400) == 0:  # 整百年能被400整除的是闰年
					yeardayc = 366
				else:  # 能被4整除的整百年且不能被400整除的是平年
					yeardayc = 365
			else:  # 非整百年能被4整除的一定是闰年
				yeardayc = 366
		else:  # 不能被4整除的一定是平年
			yeardayc = 365
		return yeardayc
	
	@classmethod
	def YearMonthDayToNumber(cls, year, month, day):
		"""计算某年某月某日是这一年的第几天"""
		monthday = [31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31]
		if cls.JudgmentYear(year) == 366:
			monthday[1] = 29
		daycount = sum(monthday[:month - 1]) + day
		return daycount
	
	@staticmethod
	def LabelmeJpgFile(jpgpath, arr2ds, masks):
		"""获取滑窗jpg文件，（先jpg后json）, 对不完整的多边形区域进行0填充处理"""
		img = cv2.merge([arr2ds[2], arr2ds[1], arr2ds[0]])
		polygonarrs = [
			np.array(polygon).astype(int) for polygon in masks]
		cv2.fillPoly(img, polygonarrs, (0, 0, 0))
		cv2.imwrite(jpgpath, img)
		return
	
	@staticmethod
	def LabelmeJsonFile(jsonpath, jpgpath, labels):
		"""获取滑窗json文件"""
		shapes = [
			{
				"label": "dapeng1",
				"line_color": None,
				"fill_color": None,
				"points": label,
				"group_id": None,
				"shape_type": "polygon",
				"flags": {}}
			for label in labels]
		with open(jpgpath, 'rb') as jpgfile:
			imagedata = jpgfile.read()
			newimagedata = base64.b64encode(imagedata).decode('utf-8')
		jpgname = os.path.split(jpgpath)[1]
		img = cv2.imread(jpgpath)
		(height, width, channels) = img.shape
		polygons = {
			"version": "4.2.10",
			"flags": {},
			"shapes": shapes,
			"lineColor": [0, 255, 0, 128],
			"fillColor": [255, 0, 0, 128],
			"imagePath": jpgname,
			"imageData": newimagedata,
			"imageHeight": height,
			"imageWidth": width}
		with open(jsonpath, 'w+') as jsonfile:
			json.dump(polygons, jsonfile, indent=4)
		return
	
	@staticmethod
	def PointSCtoPC(geot, spacepoint):
		"""根据栅格仿射参数计算空间点的像素坐标"""
		(left, xpixelsize, yangle, top, xangle, ypixelsize) = geot
		[xspacedistance, yspacedistance] = spacepoint
		pointx = (xspacedistance - left) / xpixelsize
		pointy = (yspacedistance - top) / ypixelsize
		pixelpoint = [pointx, pointy]
		return pixelpoint

	@staticmethod
	def PointPCtoSC(geot, pixelpoint):
		"""根据栅格仿射参数计算像素点的空间坐标"""
		(left, xpixelsize, yangle, top, xangle, ypixelsize) = geot
		[xpixeldistance, ypixeldistance] = pixelpoint
		pointx = left + xpixelsize * xpixeldistance + ypixeldistance * yangle
		pointy = top + ypixeldistance * ypixelsize + xpixeldistance * xangle
		spacepoint = [pointx, pointy]
		return spacepoint

	@staticmethod
	def SplitRaster(raspath, savedir):
		"""拆分栅格为多个单个波段栅格"""
		ras = gdal.Open(raspath)
		rassign = os.path.splitext(os.path.split(raspath)[1])[0]
		width, height, bandc = ras.RasterXSize, ras.RasterYSize, ras.RasterCount
		geot = ras.GetGeoTransform()
		proj = ras.GetProjection()
		srs = ras.GetSpatialRef()
		for i in tqdm(range(1, bandc + 1)):
			band = ras.GetRasterBand(i)
			arr = band.ReadAsArray(0, 0, width, height)
			novalue = band.GetNoDataValue()
			datatype = band.DataType
			bandnumstr = "0"*(2-len(str(i)))+str(i)
			rasbpath = os.path.join(savedir, rassign + "_B%s.tif" % bandnumstr)
			driver = gdal.GetDriverByName("GTiff")
			rasb = driver.Create(rasbpath, width, height, 1, datatype)
			rasb.SetGeoTransform(geot)
			rasb.SetSpatialRef(srs)
			rasb.SetProjection(proj)
			bandb = rasb.GetRasterBand(1)
			if novalue is not None:
				bandb.SetNoDataValue(novalue)
			bandb.FlushCache()
			band.FlushCache()
			del rasb
		del ras
		return

	@classmethod
	def ClipRaster(cls, rasfile, rasdir, winsize):
		"""裁剪栅格至指定目录中, 若超出边界，窗口会自适应剩余大小"""
		[xsize, ysize] = winsize
		[shape, datatype, novalue, srsw, geot, proj] = cls.GetParams(rasfile)
		rasname = os.path.split(rasfile)[1]
		sign = os.path.splitext(rasname)[0]
		rasfolder = os.path.join(rasdir, sign + r"_Clip")
		if os.path.exists(rasfolder):
			print("正在更新裁剪结果文件夹！")
		# shutil.rmtree(rasfolder)
		# os.makedirs(rasfolder)
		else:
			os.makedirs(rasfolder)
		[width, height] = shape[:-1]
		xclipc, yclipc = math.ceil(width / xsize), math.ceil(height / ysize)
		clips = [
			[xindex, yindex] for yindex in range(yclipc) for xindex in
			range(xclipc)]
		print("Start Cliping Raster:\n", rasfile)
		print("Generate Folder:\n", rasfolder)
		for index in tqdm(range(len(clips))):
			clipitem = clips[index]
			[xindex, yindex] = clipitem
			xoff, yoff = xindex * xsize, yindex * ysize
			clipid = "0" * (7 - len(str(index))) + str(index)
			name = "%s_%s_%s_%s.tif" % (clipid, sign, str(xindex), str(yindex))
			arrs = cls.ClipRasToArrs(rasfile, xoff, yoff, xsize, ysize)
			newgeot = cls.GetNewGeoTansform(geot, [xoff, yoff])
			file = cls.BuildRaster(
				rasfolder, name, newgeot, srsw, proj, arrs, datatype, novalue)
		print(rasfile, "\n Cliping Raster End!")
		return rasfolder
	
	@staticmethod
	def ImageOverlay(baseimagepath, floatimagepath, originanchor, saveimagepath):
		"""
		图像指定位置叠加
		:param baseimagepath: 底图文件路径
		:param floatimagepath: 顶图文件路径
		:param originanchor: 顶图叠加位置(中心位置参数可以设置为None, 顶图右上角为锚点)
		:param saveimagepath: 文件保存路径
		:return:
		"""
		baseimage = cv2.imread(baseimagepath)
		floatimage = cv2.imread(floatimagepath)
		(floatimageheight, floatimagewidth, floatimagechannels) = floatimage.shape
		[x, y] = originanchor
		baseimage[y:y+floatimageheight, x:x+floatimagewidth] = floatimage
		cv2.imwrite(saveimagepath, baseimage)
		return

	def ShpSrsFromRasSrs(self, raspath, dsname, layername, dsdir):
		"""
		转换shp文件指定图层的坐标系与输入栅格坐标系一致
		:param raspath: 栅格文件路径
		:param dsname: 矢量文件路径
		:param layername: 图层名称
		:param dsdir:保存矢量结果文件的文件夹
		:return:
		"""
		ds = ogr.Open(dsname)
		if layername == 0 or layername is None:
			layer = ds.GetLayer(0)
			layername = layer.GetName()
		else:
			layer = ds.GetLayerByName(layername)
		shpsrs = layer.GetSpatialRef()
		ras = gdal.Open(raspath)
		rassrs = ras.GetSpatialRef()
		rassrsname, shpsrsname = rassrs.GetName(), shpsrs.GetName()
		if rassrsname == shpsrsname:
			print("栅格与矢量坐标系一致，无需转换！")
			return [dsname, layername]
		else:
			[dsname, layername] = self.SPU.ShpToSRSGeomShp(
				dsname, layername, dsdir, rassrsw)
		return [dsname, layername]


UTL = UniversalTool()


class GOTDSV2:
	areamin = 10  # 面积阈值
	areafilter = 0  # 掩膜label面积阈值
	ratenear = 0.001  # 靠近边缘率
	nl = 7  # 前标志长度
	
	def __init__(self, rpu=RPU, spu=SPU, utl=UTL):
		self.RPU = rpu
		self.SPU = spu
		self.UTL = utl
	
	def Start(self, args):
		[raspath, dsname, lyname, dstdir, win, stride] = args
		if win is None:
			win = [1000, 1000]
		if stride is None:
			stride = win
		'''获取需要的滑窗参数'''
		slidewins = self.AllSlideWinXYnum(raspath, dstdir, win, stride)
		print("启动滑窗裁剪矢量文件。。。")
		swpolygonss = self.AllSlideWinClipShape(
			raspath, dsname, lyname, win, stride, slidewins)
		print("裁剪完毕！")
		print("启动滑窗几何分类过滤。。。")
		winspolsorts = self.AllSlideWinPolygonSort(swpolygonss, win)
		print("分类完毕！")
		print("正在生成所有jpg文件。。。")
		self.AllSlideWinJpgFlie(
			raspath, dstdir, slidewins, winspolsorts, win, stride)
		print("生成完毕！")
		print("正在生成所有json文件。。。")
		self.ALlSlideWinJsonFile(
			raspath, dstdir, slidewins, winspolsorts, win, stride)
		print("生成完毕！")
		return
	
	def ReadRastrEstimatedCostTime(self, raspath):
		"""预计耗时"""
		shape = self.RPU.GetShape(raspath)
		[width, height, channel] = shape
		costtime = 154.214135 * (3/channel) * (width/46848) * (height/31488)
		return costtime
	
	def SlideWinCount(self, raspath, win, stride):
		"""计算xy方向的滑窗次数"""
		shape = self.RPU.GetShape(raspath)
		[width, height, bandc] = shape
		[winxsize, winysize], [stridxsize, stridysize] = win, stride
		slidexc = int(math.ceil((width - winxsize) / stridxsize))
		slideyc = int(math.ceil((height - winysize) / stridysize))
		return [slidexc, slideyc]
	
	def AllSlideWinXYnum(self, raspath, dstdir, win, stride):
		"""计算滑窗数目"""
		[slidexc, slideyc] = self.SlideWinCount(raspath, win, stride)
		rasname = os.path.split(raspath)[1]
		rassign = os.path.splitext(rasname)[0]
		foldername = rassign + r"_DataSet"
		dstfolder = os.path.join(dstdir, foldername)
		slidewins = [
			[xnum, ynum] for ynum in range(slideyc) for xnum in range(slidexc)]
		goalslidewins = []
		if os.path.exists(dstfolder):
			print("启动更新数据集:", dstfolder)
			for [xnum, ynum] in slidewins:
				num = xnum + ynum * slidexc
				numstr = '0' * (self.nl - len(str(num))) + str(int(num))
				jpgname = "%s_%s.jpg" % (numstr, rassign)
				jpgpath = os.path.join(dstfolder, jpgname)
				jsonname = "%s_%s.json" % (numstr, rassign)
				jsonpath = os.path.join(dstfolder, jsonname)
				if (not os.path.exists(jpgpath)) and (not os.path.exists(jsonpath)):
					goalslidewins.append([xnum, ynum])
			print("预计更新数据最大为：%d" % len(goalslidewins))
			return goalslidewins
		else:
			print("正在创建数据集:", dstfolder)
			os.makedirs(dstfolder)
			print("预计生成数据最大为：%d" % len(slidewins))
			return slidewins
	
	def AllSlideWinClipShape(self, raspath, dsname, lyname, win, stride, slidewins):
		"""all win frame clip all shp geometrys ，get all win all pixel
		polygon list
		"""
		jgeoms = self.SPU.ShpToETJGeometrys(dsname, lyname)
		geot = self.RPU.GetGeoTransform(raspath)
		[winxsize, winysize], [stridxsize, stridysize] = win, stride
		swpolygonss = []
		for [xnum, ynum] in tqdm(slidewins):
			[xoff, yoff] = int(xnum * stridxsize), int(ynum * stridysize)
			swgeot = self.RPU.GetNewGeoTansform(geot, [xoff, yoff])
			minxpixel = int(xnum * stridxsize)
			minypixel = int(ynum * stridysize)
			maxxpixel, maxypixel = minxpixel + winxsize, minypixel + winysize
			polygonpc = [
				[minxpixel, minypixel], [maxxpixel, minypixel],
				[maxxpixel, maxypixel], [minxpixel, maxypixel]]
			polygonsc = [
				self.RPU.PointPCtoSC(geot, pixelpoint)
				for pixelpoint in polygonpc]
			wfjgeom = self.SPU.PolygonToJGeometry(polygonsc)
			swpolygons = []
			for spjgeom in jgeoms:
				spgeometry = ogr.CreateGeometryFromJson(spjgeom)
				wfgeometry = ogr.CreateGeometryFromJson(wfjgeom)
				plgeometry = wfgeometry.Intersection(spgeometry)
				geometryname = plgeometry.GetGeometryName()
				if (not plgeometry.IsEmpty()) and plgeometry.IsValid() and \
						plgeometry.IsSimple() and geometryname == "POLYGON" \
						and plgeometry.Area() > 0.0:
					swjgeom = plgeometry.ExportToJson()
					swgeomdict = json.loads(swjgeom)
					swpolygonsc = swgeomdict["coordinates"][0][:-1]
					swpolygonpc = [
						self.RPU.PointSCtoPC(swgeot, swspacepoint)
						for swspacepoint in swpolygonsc]
					swpolygons.append(swpolygonpc)
			swpolygonss.append(swpolygons)
		return swpolygonss
	
	def AccelerateClipShape(self, raspath, jgeoms, win, stride, slidewins):
		"""加速裁剪矢量，只适用于步长等于窗口大小的情况"""
		geot = self.RPU.GetGeoTransform(raspath)
		[winxsize, winysize], [stridxsize, stridysize] = win, stride
		swpolygonss = []
		jgeomc = len(jgeoms)
		jgeomindexs = range(jgeomc)
		for [xnum, ynum] in tqdm(slidewins):
			[xoff, yoff] = int(xnum * stridxsize), int(ynum * stridysize)
			swgeot = self.RPU.GetNewGeoTansform(geot, [xoff, yoff])
			minxpixel, minypixel = int(xnum * stridxsize), int(
				ynum * stridysize)
			maxxpixel, maxypixel = minxpixel + winxsize, minypixel + winysize
			polygonpc = [
				[minxpixel, minypixel], [maxxpixel, minypixel],
				[maxxpixel, maxypixel], [minxpixel, maxypixel]]
			polygonsc = [
				self.RPU.PointPCtoSC(geot, pixelpoint) for pixelpoint in
				polygonpc]
			wfjgeom = self.SPU.PolygonToJGeometry(polygonsc)
			swpolygons = []
			tmp = []
			for index in jgeomindexs:
				spjgeom = jgeoms[index]
				spgeometry = ogr.CreateGeometryFromJson(spjgeom)
				wfgeometry = ogr.CreateGeometryFromJson(wfjgeom)
				plgeometry = wfgeometry.Intersection(spgeometry)
				if (not plgeometry.IsEmpty()) and plgeometry is not None:
					swjgeom = plgeometry.ExportToJson()
					swgeomdict = json.loads(swjgeom)
					swpolygonsc = swgeomdict["coordinates"][0][:-1]
					swpolygonpc = [
						self.RPU.PointSCtoPC(swgeot, swspacepoint)
						for swspacepoint in swpolygonsc]
					swpolygons.append(swpolygonpc)
				else:
					tmp.append(index)
			jgeomindexs = tmp
			swpolygonss.append(swpolygons)
		return swpolygonss
	
	def AllSlideWinPolygonSort(self, swpolygonss, win):
		"""获取滑窗内所有polyon分类结果"""
		swpolygonsorts, [winxsize, winysize] = [], win
		for swpolygons in tqdm(swpolygonss):
			swintactpolygons, swtatterpolygons = [], []
			if not swpolygons:
				swpolygonsorts.append([[], []])
			else:
				for swpolygon in swpolygons:
					pointc = len(swpolygon)
					for pointid in range(pointc):
						point = swpolygon[pointid]
						minxnear = point[0] / winxsize
						maxxnear = abs((winxsize - point[0])) / winxsize
						minyneat = point[1] / winysize
						maxyneat = abs((winysize - point[1])) / winysize
						if point[0] < 0 or point[0] > winxsize or point[1] < 0 \
								or point[0] > winysize:
							swtatterpolygons.append(swpolygon)
							break
						elif minxnear < self.ratenear or maxxnear < self.ratenear \
								or minyneat < self.ratenear or \
								maxyneat < self.ratenear:
							swtatterpolygons.append(swpolygon)
							break
						elif pointid == pointc - 1:
							if self.UTL.Getarea(swpolygon) > self.areamin:
								swintactpolygons.append(swpolygon)
						else:
							pass
				swpolygonsorts.append([swintactpolygons, swtatterpolygons])
		return swpolygonsorts
	
	def AllSlideWinJpgFlie(self, raspath, dstdir, slidewins, winspolsorts, win, stride):
		"""生成所有滑窗jpg文件"""
		# estimatedcosttime = self.ReadRastrEstimatedCostTime(raspath)
		# print("正在载入栅格波段数据。。。(预计耗时：%f秒)" % estimatedcosttime)
		arr2ds = self.RPU.RasterToArr2ds(raspath)
		# print("载入完成！")
		[winxsize, winysize], [stridxsize, stridysize] = win, stride
		[slidexc, slideyc] = self.SlideWinCount(raspath, win, stride)
		rasname = os.path.split(raspath)[1]
		rassign = os.path.splitext(rasname)[0]
		foldername = rassign + r"_DataSet"
		dstfolder = os.path.join(dstdir, foldername)
		validindexs = [
			index for (index, value) in enumerate(winspolsorts) if value[0]]
		for index in tqdm(validindexs):
			swpolygonsortre = winspolsorts[index]
			masks, [xnum, ynum] = swpolygonsortre[1], slidewins[index]
			swarr2ds = []
			num = xnum + ynum * slidexc
			numstr = '0' * (self.nl - len(str(num))) + str(int(num))
			jpgname = "%s_%s.jpg" % (numstr, rassign)
			jpgpath = os.path.join(dstfolder, jpgname)
			for arr2d in arr2ds:
				xoff, yoff = int(xnum * stridxsize), int(ynum * stridysize)
				xend, yend = xoff + winxsize, yoff + winysize
				swarr2d = arr2d[yoff:yend, xoff:xend].copy()
				swarr2ds.append(swarr2d)
			self.UTL.LabelmeJpgFile(jpgpath, swarr2ds, masks)
		return
	
	def ALlSlideWinJsonFile(self, raspath, dstdir, slidewins, winspolsorts, win, stride):
		"""生成所有滑窗json文件"""
		[winxsize, winysize], [stridxsize, stridysize] = win, stride
		[slidexc, slideyc] = self.SlideWinCount(raspath, win, stride)
		rasname = os.path.split(raspath)[1]
		rassign = os.path.splitext(rasname)[0]
		foldername = rassign + r"_DataSet"
		dstfolder = os.path.join(dstdir, foldername)
		validindexs = [
			index for (index, value) in enumerate(winspolsorts) if value[0]]
		for index in tqdm(validindexs):
			swpolygonsortre = winspolsorts[index]
			labels, [xnum, ynum] = swpolygonsortre[0], slidewins[index]
			num = xnum + ynum * slidexc
			numstr = '0' * (self.nl - len(str(num))) + str(int(num))
			jpgname = "%s_%s.jpg" % (numstr, rassign)
			jpgpath = os.path.join(dstfolder, jpgname)
			jsonname = "%s_%s.json" % (numstr, rassign)
			jsonpath = os.path.join(dstfolder, jsonname)
			self.UTL.LabelmeJsonFile(jsonpath, jpgpath, labels)
		return
	
	
class Sentinel2:
	
	def __init__(self, utl=UTL):
		self.UTL = utl
	
	def Sentinel2ZipfileToUnzipfolder(self, zippath, unzipdir):
		"""解压哨兵2栅格文件按固定格式到至指定文件目录中"""
		'''获取哨兵2原始压缩文件名中的信息'''
		nameinfo = self.Sentinel2GetZipFileDate(zippath)
		'''构建解压文件夹'''
		unzipfolder = self.Sentinel2BuildUnzipFolderPath(
			zippath, nameinfo, unzipdir)
		'''获取压缩文件命列表'''
		zipfilenames = self.Sentinel2UnzipRasterNames(zippath)
		'''解压列表中的文件'''
		self.UnzipFileToFolder(zippath, unzipfolder, zipfilenames)
		'''文件重命名'''
		self.Sentinel2RasterFilesRename(unzipfolder)
		return
	
	@staticmethod
	def Sentinel2GetZipFileDate(zippath):
		"""获取哨兵2原始压缩文件名中的信息"""
		if not os.path.exists(zippath):
			return print(zippath, "\n该路径不存在！")
		filedir, filename = os.path.split(zippath)
		name, extend = os.path.splitext(filename)
		signstrs = name.split("_")
		satellite, product = signstrs[0], signstrs[1]
		zoneid, date = signstrs[-2], signstrs[-1][:8]
		return [satellite, product, zoneid, date]
	
	def Sentinel2BuildUnzipFolderPath(self, zippath, nameinfo, unzipdir):
		"""依据指定格式创建哨兵2解压文件夹"""
		[satellite, product, zoneid, date] = nameinfo
		year, month, day = int(date[:4]), int(date[4:6]), int(date[6:])
		dayc = self.UTL.YearMonthDayToNumber(year, month, day)
		foldername = "%s_%s_%s_%s_%d" % (satellite, product, zoneid, date, dayc)
		unzipfolder = os.path.join(unzipdir, foldername)
		if os.path.exists(unzipfolder):
			return print(unzipfolder, ":解压文件夹存在！")
		else:
			os.makedirs(unzipfolder)
		return unzipfolder
	
	@staticmethod
	def Sentinel2UnzipRasterNames(zipfilepath):
		"""获取需要解压的哨兵2压缩文件中文件列表"""
		allzipfile = zipfile.ZipFile(zipfilepath, "r")
		allfiles = allzipfile.namelist()
		'''获取压缩文件中的指定波段文件列表'''
		band8jpgfiles = []
		for i in range(1, 9):
			pattern = re.compile("_B0[%d](.)*\.jp2" % i)
			bandjp2s = [file for file in allfiles if re.search(pattern, file)]
			if len(bandjp2s) >= 2:
				rasfilepres = []
				for bandjp2 in bandjp2s:
					jp2filename = os.path.split(bandjp2)[1]
					filename = os.path.splitext(jp2filename)[0]
					rasfilepres.append(int(filename.split("_")[-1][:-1]))
				goalindex = rasfilepres.index(min(rasfilepres))
				band8jpgfiles.append(bandjp2s[goalindex])
			else:
				band8jpgfiles.append(bandjp2s[0])
		return band8jpgfiles
	
	@staticmethod
	def UnzipFileToFolder(zipfilepath, unzipfolder, zipfilenames=None):
		"""依据列表解压压缩文件中的文件到指定的新建文件夹下"""
		allzipfile = zipfile.ZipFile(zipfilepath, "r")
		if zipfilenames is None:
			zipfilenames = allzipfile.namelist()
		for zipfilename in zipfilenames:
			allzipfile.extract(zipfilename, unzipfolder)
			file = os.path.join(unzipfolder, zipfilename)
			filename = os.path.split(zipfilename)[1]
			newfile = os.path.join(unzipfolder, filename)
			shutil.move(file, newfile)
		allzipfile.close()
		foldernames = os.listdir(unzipfolder)
		for foldername in foldernames:
			folder = os.path.join(unzipfolder, foldername)
			if os.path.isdir(folder):
				shutil.rmtree(folder)
		return
	
	@staticmethod
	def Sentinel2RasterFilesRename(unzipfolder):
		"""依据文件夹的名字修改每个波段栅格文件名"""
		filenames = os.listdir(unzipfolder)
		foldername = os.path.split(unzipfolder)[1]
		for i in range(1, 9):
			pattern = re.compile('_(.)*_B0%d(.)*\.jp2' % i)
			filenames = os.listdir(unzipfolder)
			for filename in filenames:
				if re.search(pattern, filename):
					extend = os.path.splitext(filename)[1]
					filepath = os.path.join(unzipfolder, filename)
					newfilename = "%s_B0%d%s" % (foldername, i, extend)
					newfilepath = os.path.join(unzipfolder, newfilename)
					os.rename(filepath, newfilepath)
		return
	
	def Zone8BandResampling(self, zonefolder, savedir):
		"""对提取后原始哨兵影像进行重采样，使所有栅格分辨率都与最高的栅格一致！"""
		foldername = os.path.split(zonefolder)[1]
		outzonefolder = os.path.join(savedir, foldername)
		if not os.path.exists(outzonefolder):
			os.makedirs(outzonefolder)
		raspaths = self.UTL.GetGoalFile(zonefolder, r".jp2")
		filenames = os.listdir(zonefolder)
		pres, geots = [], []
		for filename in filenames:
			rasfile = os.path.join(zonefolder, filename)
			ras = gdal.Open(rasfile)
			geot = ras.GetGeoTransform()
			pres.append(abs(geot[1]))
			geots.append(geot)
			del ras
		standardindex = pres.index(min(pres))
		goalgeot = geots[standardindex]
		for filename in filenames:
			rasfile = os.path.join(zonefolder, filename)
			self.UTL.RasterReshapeByGeo(rasfile, goalgeot, outzonefolder)
		print(outzonefolder)
		return

	@staticmethod
	def Zone8BandCompose(zonefolder, savefolder):
		"""组合哨兵前8波段"""
		rasnames = os.listdir(zonefolder)
		bandc = len(rasnames)
		srassign = os.path.splitext(rasnames[0])[0]
		signstrs = srassign.split("_")[:-1]
		rrassign = "_".join(signstrs)
		rrasname = rrassign + ".tif"
		sraspath = os.path.join(zonefolder, rasnames[0])
		sras = gdal.Open(sraspath)
		width, height = sras.RasterXSize, sras.RasterYSize
		geot, srs = sras.GetGeoTransform(), sras.GetSpatialRef()
		proj = sras.GetProjectionRef()
		datatype = sras.GetRasterBand(1).DataType
		del sras
		arr2ds = []
		for i in range(1, bandc+1):
			trasname = rrassign+ "_B0%d.tif" % i
			traspath = os.path.join(zonefolder, trasname)
			tras = gdal.Open(traspath)
			arr2ds.append(tras.GetRasterBand(1).ReadAsArray(0, 0, width, height))
			del tras
		rraspath = os.path.join(savefolder, rrasname)
		driver = gdal.GetDriverByName("GTiff")
		rras = driver.Create(rraspath, width, height, bandc, datatype)
		rras.SetGeoTransform(geot), rras.SetSpatialRef(srs), rras.SetProjection(proj)
		[rras.GetRasterBand(i + 1).WriteArray(arr2ds[i]) for i in range(bandc)]
		del rras
		return
	

STL2 = Sentinel2()


class DataPU:
	matchstr = r'_B0[1-8](.*)[\.]jp2'
	geomtype = ogr.wkbPolygon
	wgs84str = (
			"GEOGCS[\"WGS 84\"," +
			"DATUM[\"World Geodetic System 1984\"," +
			"SPHEROID[\"WGS 84\",6378137,298.257223563]]," +
			"PRIMEM[\"Greenwich\",0]," +
			"UNIT[\"degree\",0.0174532925199433]," +
			"AXIS[\"Longitude\",EAST],AXIS[\"Latitude\",NORTH]]"
	)
	sentinelunzipdir = r"/home/fyy_dapeng/sourcedata/sourceunzip"
	sentinelzipdir = r"/home/fyy_dapeng/sourcedata/sourcezip/Sentinel2Zip"
	sentinelsinglebandrasdir = r"/home/fyy_dapeng/resultdata/Sentinel2_8Band_10m"
	citylabelshpsdir = r"/home/fyy_dapeng/sourcedata/sourceshp/2020"
	croplabelshpsdir = r"/home/fyy_dapeng/sourcedata/sourcelabel"
	crop = r"玉米"
	year = r"2020"
	
	def __init__(self, raspu=RPU, shppu=SPU, tul=UTL, s3pu=S3PU):
		self.RPU = raspu
		self.SPU = shppu
		self.S3PU = s3pu
		self.UTL = tul

	def MultipleImageOverlay(self, baseimagepath, floatimagepathlist, savedir):
		"""
        在底图上叠加两个图像
        :param baseimagepath: 底图
        :param floatimagepathlist: 顶图文件列表
        :param savedir: 保存路径
        :return:
        """
		[floatimagepath1, floatimagepath2] = floatimagepathlist
		baseimage = cv2.imread(baseimagepath)
		floatimage1 = cv2.imread(floatimagepath1)
		floatimage2 = cv2.imread(floatimagepath2)
		(baseimageheight, baseimagewidth, baseimagechannels) = baseimage.shape
		(floatimage1height, floatimage1width, floatimage1channels) = floatimage1.shape
		(floatimage2height, floatimage2width, floatimage2channels) = floatimage2.shape
		floatimage1originanchor = [
			int(baseimagewidth / 2 - floatimage1width / 2),
			int(baseimageheight / 2 - floatimage1height - floatimage1height / 2)]
		floatimage2originanchor = [
			int(baseimagewidth / 2 - floatimage2width / 2),
			int(baseimageheight / 2 + floatimage2height + floatimage2height / 2)]
		baseimagename = os.path.split(baseimagepath)[1]
		newbaseimagepath = os.path.join(savedir, baseimagename)
		self.UTL.ImageOverlay(baseimagepath, floatimagepath1, floatimage1originanchor, newbaseimagepath)
		self.UTL.ImageOverlay(newbaseimagepath, floatimagepath2, floatimage2originanchor, newbaseimagepath)
		polygon1 = [
			floatimage1originanchor,
			[floatimage1originanchor[0] + floatimage1width, floatimage1originanchor[1]],
			[floatimage1originanchor[0] + floatimage1width, floatimage1originanchor[1] + floatimage1height],
			[floatimage1originanchor[0], floatimage1originanchor[1] + floatimage1height]]
		polygon2 = [
			floatimage2originanchor,
			[floatimage2originanchor[0] + floatimage2width, floatimage2originanchor[1]],
			[floatimage2originanchor[0] + floatimage2width, floatimage2originanchor[1] + floatimage2height],
			[floatimage2originanchor[0], floatimage2originanchor[1] + floatimage2height]]
		labels = [polygon1, polygon2]
		return [newbaseimagepath, labels]

	def LabelmeJsonSort(self, jsonpath, floatimgpaths,  savedir1, savedir2):
		"""labelme json文件赛查分类"""
		with open(jsonpath, 'r') as jsonfile:
			jsondict = json.load(jsonfile)
			lablec = len(jsondict["shapes"])
			if lablec == 0:
				jpgpath = jsonpath.replace(".json", ".jpg")
				jpgname = os.path.split(jpgpath)[1]
				jsonname = os.path.split(jsonpath)[1]
				newjpgpath = os.path.join(savedir1, jpgname)
				newjsonpath = os.path.join(savedir1, jsonname)
				[floatimgpath1, floatimgpath2] = floatimgpaths
				shutil.copyfile(jpgpath, newjpgpath)
				shutil.copyfile(jpgpath, newjsonpath)
				[newimg2, labels] = self.CompositeSample(
					newjpgpath, floatimgpath1, floatimgpath2, savedir1)
				self.UTL.LabelmeJsonFile(newjsonpath, newimg2, labels)
			else:
				jpgpath = jsonpath.replace(".json", ".jpg")
				jpgname = os.path.split(jpgpath)[1]
				jsonname = os.path.split(jsonpath)[1]
				newjpgpath = os.path.join(savedir2, jpgname)
				newjsonpath = os.path.join(savedir2, jsonname)
				shutil.copyfile(jpgpath, newjpgpath)
				shutil.copyfile(jpgpath, newjsonpath)
		return
	
	def CompositeSample(self, baseimgpath, floatimgpath1, floatimgpath2, savedir):
		"""合成含有两个标签的样本数据"""
		baseimage = cv2.imread(baseimgpath)
		floatimage1 = cv2.imread(floatimgpath1)
		floatimage2 = cv2.imread(floatimgpath2)
		(heightb, widthb, channelsb) = baseimage.shape
		(height1, width1, channels1) = floatimage1.shape
		(height2, width2, channels2) = floatimage2.shape
		baseimagecenter = [widthb/2, heightb/2]
		floatimage1center = [width1/2, height1/2]
		floatimage2center = [width2/2, height2/2]
		xoff1 = (widthb/2)-(width1/2)
		yoff1 = (heightb/2)- height1 - (height1/2)
		xoff2 =(widthb/2) - (width1/2)
		yoff2 =(heightb/2) + height2 + (height2/2)
		startoff1 = [int(xoff1), int(yoff1)]
		startoff2 = [int(xoff2), int(yoff2)]
		newimg1 = self.UTL.ImgRIOAddImg(
			baseimgpath, floatimgpath1, savedir, startoff1)
		newimg2 = self.UTL.ImgRIOAddImg(
			newimg1, floatimgpath2, savedir,  startoff2)
		polygon1 = [
			[xoff1, yoff1],
			[xoff1 + width1, yoff1],
			[xoff1 + width1, yoff1 + height1],
			[xoff1, yoff1 + height1]]
		polygon2 = [
			[xoff2, yoff2],
			[xoff2 + width2, yoff2],
			[xoff2 + width2, yoff2 + height2],
			[xoff2, yoff2 + height2]]
		labels = [polygon1, polygon2]
		return [newimg2, labels]
	
	def CountySentinelInfoToJson(self, infodict, savedir=None, jsonsign=None):
		"""创建县城与哨兵2关系的json文件"""
		savedir = r"/home/fyy_dapeng/resultdata/Config"
		jsonsign = r"Sentinel2CountyInfo"
		jsonpath = os.path.join(savedir, jsonsign + r".json")
		if os.path.exists(jsonpath):
			with open(jsonpath, 'r', encoding="utf-8") as jsonfile:
				jsondata = json.load(jsonfile)
				try:
					jsondata.index(infodict)
					return print("该条记录存在，添加失败！")
				except BaseException:
					jsondata.append(infodict)
			with open(jsonpath, 'w', encoding="utf-8") as jsonfile:
				json.dump(jsondata, jsonfile, ensure_ascii=False, indent=4)
		else:
			self.UTL.DictToJsonFile(savedir, jsonsign, [infodict])
		return
	
	def BatchUnzipSentinel2(self, zipsdir=None, unzipsdir=None):
		"""根据县市文件夹下各自原始哨兵zip文件批量解压至相应县市目录下"""
		if zipsdir is None:
			zipsdir = r"/home/fyy_dapeng/sourcedata/sourcezip/Sentinel2Zip"
		if unzipsdir is None:
			unzipsdir = r"/home/fyy_dapeng/sourcedata/sourceunzip"
		zonenames = os.listdir(zipsdir)
		[
			os.makedirs(os.path.join(unzipsdir, zonename))
			for zonename in os.listdir(zipsdir)
			if not os.path.exists(os.path.join(unzipsdir, zonename))]
		print("启动批量解压！")
		for zonename in tqdm(zonenames):
			zonezipsdir = os.path.join(zipsdir, zonename)
			zippaths = self.GetGoalFile(zonezipsdir, r".zip")
			unzipfolder = os.path.join(unzipsdir, zonename)
			[self.UnzipFile(zippath, unzipfolder) for zippath in zippaths]
		print("完成批量解压！")
		return
	
	def BatchFilterSentinel2BandTo10m(self, unzipsdir=None, zonesdir=None):
		"""批量从各县市原始哨兵解压文件中获取并重采样目标栅格影像至新路径下对应县市目录"""
		if unzipsdir is None:
			unzipsdir = r"/home/fyy_dapeng/sourcedata/sourceunzip"
		if zonesdir is None:
			zonesdir = r"/home/fyy_dapeng/resultdata/Sentinel2_8Band_10m"
		zonenames = os.listdir(unzipsdir)
		[
			os.makedirs(os.path.join(zonesdir, zonename))
			for zonename in os.listdir(unzipsdir)
			if not os.path.exists(os.path.join(zonesdir, zonename))]
		print("启动波段筛选重采样！")
		for zonename in tqdm(zonenames):
			zoneunzipdir = os.path.join(unzipsdir, zonename)
			zonetimenames = os.listdir(zoneunzipdir)
			zonedir = os.path.join(zonesdir, zonename)
			for zonetimename in zonetimenames:
				zonetimedir = os.path.join(zoneunzipdir, zonetimename)
				zonetimedircp = os.path.join(zonedir, zonetimename)
				shutil.copytree(zonetimedir, zonetimedircp)
				self.WashDirSaveGoalFiles(zonetimedircp, self.matchstr)
				self.ChoiceGoalFile(zonetimedircp)
				newname = "%s_%s" % (
					zonetimename.split("_")[5], zonetimename.split("_")[6][:8])
				newfolder = os.path.join(zonedir, newname)
				if not os.path.exists(newfolder):
					shutil.move(zonetimedircp, newfolder)
				attrs = self.GetHeightRasAttrs(newfolder, 10)
				self.BatchReshappeRas(newfolder, newfolder, attrs)
		print("完成波段筛选重采样！")
		return
	
	def Sentinel2Lalbel(self):
		citydirnames = os.listdir(self.sentinelsinglebandrasdir)
		for citydirname in citydirnames:
			citydir = os.path.join(citydirname, self.sentinelsinglebandrasdir)
			zonedirnames = os.listdir(citydir)
			for zonedirname in zonedirnames:
				zonedir = os.path.join(citydir, zonedirname)
				timedirnames = os.listdir(zonedir)
				timedir = os.path.join(zonedir, timedirnames[0])
		return
	
	def BuildSentinel2DB(self, citysdir):
		"""构建并跟新哨兵图幅信息表"""
		self.S3PU.CreateDB(flage=False)
		self.S3PU.CreateTabel(flage=False)
		datalist = self.BuildSentinel2SrcData(citysdir)
		self.S3PU.InsertRecording(datalist)
		self.S3PU.PrintTable()
		return
	
	def SentinelRasterTB(self, dbdir, dbname, tbname, datalist):
		"""构建并更新城市与哨兵2图幅编号关系表"""
		tbheader = [
			["citycode", "varchar(20)"],
			["cityname", "varchar(20)"],
			["zonename", "varchar(20)"]]
		dbpath = os.path.join(dbdir, dbname)
		self.S3PU.CreateDB(dbdir, dbname, flage=False)
		self.S3PU.CreateTabel(dbpath, tbname, tbheader, flage=False)
		tablestructure = self.S3PU.GetTableStructure(dbpath, tbname)
		for dataitem in datalist:
			fdvalue0, fdvalue2 = dataitem[0], dataitem[2]
			fileddicts = [["citycode", fdvalue0], ["zonename", fdvalue2]]
			result = self.S3PU.SelectRecordings(dbpath, tbname, fileddicts)
			if len(result) >= 1:
				print(result, "该记录存在！，记录插入失败！")
			else:
				self.S3PU.InsertRecording(datalist, dbpath, tbname)
		self.S3PU.PrintTable(dbpath, tbname)
		return
	
	def BuildSentinel2SrcData(self, citysdir):
		"""依据的单波段哨兵影像原始名称构建，哨兵图幅信息数据列表"""
		'''获取所有jp2文件路径'''
		filepaths = self.FindAllFile(citysdir)
		filepathc = len(filepaths)
		zonenames = []
		for filepathindex in range(filepathc):
			filepath = filepaths[filepathindex]
			filename = os.path.split(filepath)[1]
			filesign = os.path.splitext(filename)[0]
			zonename = filesign.split("_")[0]
			zonenames.append(zonename)
		onlyvaluezonenames = set(zonenames)
		onlyvaluezonenamesindexs = [
			zonenames.index(onlyvaluezonename)
			for onlyvaluezonename in onlyvaluezonenames]
		datalist = []
		for indexitem in onlyvaluezonenamesindexs:
			filepath = filepaths[indexitem]
			zonename = zonenames[indexitem]
			ras = gdal.Open(filepath)
			width = ras.RasterXSize
			height = ras.RasterYSize
			geotr = list(ras.GetGeoTransform())
			srsew = ras.GetSpatialRef()
			print(srsew)
			dataitem = [zonename, width, height] + geotr
			datalist.append(dataitem)
		return datalist
	
	def BuildSentinel2SRSw(self, citysdir):
		"""依据的单波段哨兵影像原始名称构建，哨兵图幅信息数据列表"""
		'''获取所有jp2文件路径'''
		filepaths = self.FindAllFile(citysdir)
		filepathc = len(filepaths)
		zonenames = []
		for filepathindex in range(filepathc):
			filepath = filepaths[filepathindex]
			filename = os.path.split(filepath)[1]
			filesign = os.path.splitext(filename)[0]
			zonename = filesign.split("_")[0]
			zonenames.append(zonename)
		onlyvaluezonenames = set(zonenames)
		onlyvaluezonenamesindexs = [
			zonenames.index(onlyvaluezonename)
			for onlyvaluezonename in onlyvaluezonenames]
		datalist = {}
		for indexitem in onlyvaluezonenamesindexs:
			filepath = filepaths[indexitem]
			zonename = zonenames[indexitem]
			ras = gdal.Open(filepath)
			srsew = ras.GetSpatialRef().ExportToWkt()
			datalist[zonename] = srsew
			del ras
		return datalist
	
	def BuildSentinel2OnlyRas(self, citysdir):
		"""依据的单波段哨兵影像原始名称构建，哨兵图幅信息数据列表"""
		'''获取所有jp2文件路径'''
		filepaths = self.FindAllFile(citysdir)
		filepathc = len(filepaths)
		zonenames = []
		for filepathindex in range(filepathc):
			filepath = filepaths[filepathindex]
			filename = os.path.split(filepath)[1]
			filesign = os.path.splitext(filename)[0]
			zonename = filesign.split("_")[0]
			zonenames.append(zonename)
		onlyvaluezonenames = set(zonenames)
		onlyvaluezonenamesindexs = [
			zonenames.index(onlyvaluezonename)
			for onlyvaluezonename in onlyvaluezonenames]
		datalist = []
		for indexitem in onlyvaluezonenamesindexs:
			filepath = filepaths[indexitem]
			zonename = zonenames[indexitem]
			cityname = os.path.split(os.path.split(os.path.split(os.path.split(
				filepath)[0])[0])[0])[1]
			datalist.append([cityname, filepath])
		return datalist
	 
	def BatchFilterShapeLabel(self, citylabelshpsdir, croplabelshpsdir, sentinelsdir, dsdir, rasdir):
		"""批量转换矢量文件为栅格文件，需要栅格文件的帮助，临时工具"""
		shpdirnames = os.listdir(citylabelshpsdir)
		for shpdirname in shpdirnames:
			dsname = os.path.join(citylabelshpsdir, shpdirname)
			pattern = re.compile(self.crop)
			if re.search(pattern, shpdirname):
				pattern = re.compile("\d")
				cityqhdm = ""
				for i in re.findall(pattern, shpdirname):
					cityqhdm = cityqhdm + i
				cityname = shpdirname.replace(cityqhdm, "").replace(self.crop,
				                                                    "")
				yearcitydirname = self.year + r"_" + cityqhdm + r"_" + cityname + r"_" + self.crop
				yearcitydir = os.path.join(croplabelshpsdir, yearcitydirname)
				if not os.path.exists(yearcitydir):
					os.makedirs(yearcitydir)
				ds = ogr.Open(dsname)
				layer = ds.GetLayer()
				layername = layer.GetName()
				ds.Destroy()
				nameraspaths = self.BuildSentinel2OnlyRas(sentinelsdir)
				for nameraspath in nameraspaths:
					[signname, raspath] = nameraspath
					print(signname)
					print(cityname)
					if signname == cityname:
						newraspath = self.SPU.ShpToRas(
							dsname, layername, dsdir, raspath, rasdir)
		return
	
	def BLFieldToRas(self, citylabelshpsdir, croplabelshpsdir, sentinelsdir, dsdir, rasdir):
		"""批量转换矢量文件为栅格文件，需要栅格文件的帮助，临时工具"""
		shpdirnames = os.listdir(citylabelshpsdir)
		for shpdirname in shpdirnames:
			dsname = os.path.join(citylabelshpsdir, shpdirname)
			pattern = re.compile(self.crop)
			if re.search(pattern, shpdirname):
				pattern = re.compile("\d")
				cityqhdm = ""
				for i in re.findall(pattern, shpdirname):
					cityqhdm = cityqhdm + i
				cityname = shpdirname.replace(cityqhdm, "").replace(self.crop,
				                                                    "")
				yearcitydirname = self.year + r"_" + cityqhdm + r"_" + cityname + r"_" + self.crop
				yearcitydir = os.path.join(croplabelshpsdir, yearcitydirname)
				if not os.path.exists(yearcitydir):
					os.makedirs(yearcitydir)
				ds = ogr.Open(dsname)
				layer = ds.GetLayer()
				layername = layer.GetName()
				ds.Destroy()
				nameraspaths = self.BuildSentinel2OnlyRas(sentinelsdir)
				for nameraspath in nameraspaths:
					[signname, raspath] = nameraspath
					print(signname)
					print(cityname)
					if signname == cityname:
						newraspath = self.SPU.ShpToRas(
							dsname, layername, dsdir, raspath, rasdir)
		return
	
	@classmethod
	def CreateFolderTree(cls, indir=None, outdir=None):
		"""依据压缩文件创建相应城市、图幅编号、时期的目录树"""
		if indir is None:
			indir = r"/home/fyy_dapeng/sourcedata/sourcezip/Sentinel2Zip"
		if outdir is None:
			outdir = r"/home/fyy_dapeng/resultdata/Zone__Normalized"
		citynames = os.listdir(indir)
		for cityname in citynames:
			outcitydir = os.path.join(outdir, cityname)
			if not os.path.exists(outcitydir):
				os.makedirs(outcitydir)
			citydir = os.path.join(indir, cityname)
			zonetimenames = os.listdir(citydir)
			for zonetimename in zonetimenames:
				zonename = zonetimename.split("_")[5]
				zonedir = os.path.join(outcitydir, zonename)
				if not os.path.exists(zonedir):
					os.makedirs(zonedir)
				timename = zonetimename.split("_")[6][:8]
				timedir = os.path.join(zonedir, timename)
				if not os.path.exists(timedir):
					os.makedirs(timedir)
		return
	
	def Sentinel2ZipBatch(self, zipdir=None, unzipdir=None, outdir=None):
		if zipdir is None:
			zipdir = self.sentinelzipdir
		if unzipdir is None:
			unzipdir = self.sentinelunzipdir
		if outdir is None:
			outdir = self.sentinelsinglebandrasdir
		self.CreateFolderTree(zipdir, outdir)
		self.BatchUnzipSentinel2(zipdir, unzipdir)
		self.BatchZoneTimeToBand(unzipdir, outdir)
		return
	
	def BatchZoneTimeToBand(self, unzipsdir, outdir):
		if unzipsdir is None:
			unzipsdir = r"/home/fyy_dapeng/sourcedata/sourceunzip"
		if outdir is None:
			outdir = r"/home/fyy_dapeng/resultdata/Sentinel2_8Band_10m"
		citynames = os.listdir(unzipsdir)
		for cityname in citynames:
			citydir = os.path.join(unzipsdir, cityname)
			outcitydir = os.path.join(outdir, cityname)
			zonetimenames = os.listdir(citydir)
			print(citydir, ":启动波段筛选重采样！")
			for zonetimename in tqdm(zonetimenames):
				zonename = zonetimename.split("_")[5]
				timename = zonetimename.split("_")[6][:8]
				zonedir = os.path.join(outcitydir, zonename)
				timedir = os.path.join(zonedir, timename)
				if len(os.listdir(timedir)) == 0:
					zonetimedir = os.path.join(citydir, zonetimename)
					self.CopyDirToExistDir(zonetimedir, timedir)
					self.WashDirSaveGoalFiles(timedir, self.matchstr)
					self.ChoiceGoalFile(timedir)
					attrs = self.GetHeightRasAttrs(timedir, 10)
					self.BatchReshappeRas(timedir, timedir, attrs)
			print(citydir, ":完成波段筛选重采样！")
		return
	
	def GetRasTDS(self, zipsdir, outdir):
		"""解压栅格文件压缩文件，并转换数据为训练数据或预测数据至，指定文件夹下"""
		tmpdir = os.path.join(os.path.split(zipsdir)[0], r"Raster_TEMP")
		if os.path.exists(tmpdir):
			shutil.rmtree(tmpdir)
			os.makedirs(tmpdir)
		else:
			os.makedirs(tmpdir)
		self.BatchZipToBandNDVIr(zipsdir, tmpdir)
		self.RasToLib(tmpdir, outdir)
		shutil.rmtree(tmpdir)
		return
	
	def RasToLib(self, indir, outdir):
		"""从单幅同时期的raster dir提取同幅多时期栅格，归一化存放同文件夹下"""
		numtimedirns = os.listdir(indir)
		print("启动栅格波段数据移动、归一化处理。。。")
		for ntdirn in tqdm(numtimedirns):
			ntpath = os.path.join(indir, ntdirn)
			rasns = os.listdir(ntpath)
			npath = os.path.join(outdir, ntdirn.split("_")[0])
			if os.path.exists(npath):
				for rasn in rasns:
					dstraspath = os.path.join(npath, rasn)
					if os.path.exists(dstraspath):
						os.remove(dstraspath)
					else:
						srcraspath = os.path.join(ntpath, rasn)
						shutil.move(srcraspath, dstraspath)
			else:
				os.makedirs(npath)
				for rasn in rasns:
					dstraspath = os.path.join(npath, rasn)
					srcraspath = os.path.join(ntpath, rasn)
					shutil.move(srcraspath, dstraspath)
			self.RassToNormRass(npath)
		print("完成栅格波段数据移动、归一化处理！")
		return
	
	def WashDirSaveGoalFiles(self, folder, matchstr):
		"""筛选哨兵解压目录中的1-8波段栅格影像,但有可能保存重复波段但不同精度影像"""
		[basedir, foldername] = os.path.split(folder)
		tmpfolder = os.path.join(basedir, foldername + r"_tmp")
		shutil.move(folder, tmpfolder)
		os.makedirs(folder)
		pattern = re.compile(matchstr)
		files = self.FindAllFile(tmpfolder)
		for file in files:
			filename = os.path.split(file)[1]
			if re.search(pattern, filename):
				newfile = os.path.join(folder, filename)
				if not os.path.exists(newfile):
					shutil.move(file, newfile)
		shutil.rmtree(tmpfolder)
		return
	
	def Sentinel2ZipfileToUnzipfolder(self, zippath, unzipdir):
		"""解压哨兵2栅格文件按固定格式到至指定文件目录中"""
		'''获取哨兵2原始压缩文件名中的信息'''
		nameinfo = self.Sentinel2GetZipFileDate(zippath)
		'''构建解压文件夹'''
		unzipfolder = self.Sentinel2BuildUnzipFolderPath(
			zippath, nameinfo, unzipdir)
		'''获取压缩文件命列表'''
		zipfilenames = self.Sentinel2UnzipRasterNames(zippath)
		'''解压列表中的文件'''
		self.UnzipFileToFolder(zippath, unzipfolder, zipfilenames)
		'''文件重命名'''
		self.Sentinel2RasterFilesRename(unzipfolder)
		return
	
	@staticmethod
	def Sentinel2GetZipFileDate(zippath):
		"""获取哨兵2原始压缩文件名中的信息"""
		if not os.path.exists(zippath):
			return print(zippath, "\n该路径不存在！")
		filedir, filename = os.path.split(zippath)
		name, extend = os.path.splitext(filename)
		signstrs = name.split("_")
		satellite, product = signstrs[0], signstrs[1]
		zoneid, date = signstrs[-2], signstrs[-1][:8]
		return [satellite, product, zoneid, date]
	
	def Sentinel2BuildUnzipFolderPath(self, zippath, nameinfo, unzipdir):
		"""依据指定格式创建哨兵2解压文件夹"""
		[satellite, product, zoneid, date] = nameinfo
		year, month, day = int(date[:4]), int(date[4:6]), int(date[6:])
		dayc = self.UTL.YearMonthDayToNumber(year, month, day)
		foldername = "%s_%s_%s_%s_%d" % (satellite, product, zoneid, date, dayc)
		unzipfolder = os.path.join(unzipdir, foldername)
		if os.path.exists(unzipfolder):
			return print(unzipfolder, ":解压文件夹存在！")
		else:
			os.makedirs(unzipfolder)
		return unzipfolder
	
	@staticmethod
	def Sentinel2UnzipRasterNames(zipfilepath):
		"""获取需要解压的哨兵2压缩文件中文件列表"""
		allzipfile = zipfile.ZipFile(zipfilepath, "r")
		allfiles = allzipfile.namelist()
		'''获取压缩文件中的指定波段文件列表'''
		band8jpgfiles = []
		for i in range(1, 9):
			pattern = re.compile("_B0[%d](.)*\.jp2" % i)
			bandjp2s = [file for file in allfiles if re.search(pattern, file)]
			if len(bandjp2s) >= 2:
				rasfilepres = []
				for bandjp2 in bandjp2s:
					jp2filename = os.path.split(bandjp2)[1]
					filename = os.path.splitext(jp2filename)[0]
					rasfilepres.append(int(filename.split("_")[-1][:-1]))
				goalindex = rasfilepres.index(min(rasfilepres))
				band8jpgfiles.append(bandjp2s[goalindex])
			else:
				band8jpgfiles.append(bandjp2s[0])
		return band8jpgfiles
	
	@staticmethod
	def UnzipFileToFolder(zipfilepath, unzipfolder, zipfilenames=None):
		"""依据列表解压压缩文件中的文件到指定的新建文件夹下"""
		allzipfile = zipfile.ZipFile(zipfilepath, "r")
		if zipfilenames is None:
			zipfilenames = allzipfile.namelist()
		for zipfilename in zipfilenames:
			allzipfile.extract(zipfilename, unzipfolder)
			file = os.path.join(unzipfolder, zipfilename)
			filename = os.path.split(zipfilename)[1]
			newfile = os.path.join(unzipfolder, filename)
			shutil.move(file, newfile)
		allzipfile.close()
		foldernames = os.listdir(unzipfolder)
		for foldername in foldernames:
			folder = os.path.join(unzipfolder, foldername)
			if os.path.isdir(folder):
				shutil.rmtree(folder)
		return
	
	@staticmethod
	def Sentinel2RasterFilesRename(unzipfolder):
		"""依据文件夹的名字修改每个波段栅格文件名"""
		filenames = os.listdir(unzipfolder)
		foldername = os.path.split(unzipfolder)[1]
		for i in range(1, 9):
			pattern = re.compile('_(.)*_B0%d(.)*\.jp2' % i)
			filenames = os.listdir(unzipfolder)
			for filename in filenames:
				if re.search(pattern, filename):
					extend = os.path.splitext(filename)[1]
					filepath = os.path.join(unzipfolder, filename)
					newfilename = "%s_B0%d%s" % (foldername, i, extend)
					newfilepath = os.path.join(unzipfolder, newfilename)
					os.rename(filepath, newfilepath)
		return
	
	@classmethod
	def Sentinel2HeightResolutionInfo(cls, unzipfolder):
		"""获取哨兵2解压栅格文件高分参数"""
		raspaths = cls.GetGoalFile(unzipfolder, r".jp2")
		pres = []
		for raspath in raspaths:
			ras = gdal.Open(raspath)
			pres.append(abs(ras.GetGeoTransform()[1]))
			del ras
		standardindex = pres.index(min(pres))
		goalrasfile = raspaths[standardindex]
		ras = gdal.Open(goalrasfile)
		shape = [ras.RasterXSize, ras.RasterYSize]
		geot, proj = ras.GetGeoTransform(), ras.GetProjection()
		srsw = ras.GetSpatialRef().ExportToWkt()
		datatype = ras.GetRasterBand(1).DataType
		novalue = ras.GetRasterBand(1).GetNoDataValue()
		rasinfo = [shape, geot, proj, srsw, datatype, novalue]
		return rasinfo
	
	def Sentinel2Resampling(self, unzipfolder, dstdir=None, flag=False):
		"""对解压后的哨兵影像进行重采样，使所有栅格分辨率都与最高的栅格一致！"""
		rasinfo = self.Sentinel2HeightResolutionInfo(unzipfolder)
		[shape, geot, proj, srsw, datatype, novalue] = rasinfo
		filenames = os.listdir(unzipfolder)
		foldername = os.path.split(unzipfolder)[1]
		if dstdir is None:
			dstfolder = unzipfolder
		else:
			dstfolder = os.path.join(dstdir, foldername)
		for filename in filenames:
			file = os.path.join(unzipfolder, filename)
			ras = gdal.Open(file)
			if shape[0] != ras.RasterXSize and shape[1] != ras.RasterYSize:
				arrs = self.RasterToReshapeArr2ds(file, shape)
				name = os.path.splitext(filename)[0] + ".tif"
				self.RPU.BuildRaster(
					dstfolder, name, geot, srsw, proj, arrs, datatype, novalue)
				if not flag:
					os.move(file)
		return
	
	@staticmethod
	def ChoiceGoalFile(timedir):
		bandnames = os.listdir(timedir)
		for i in range(1, 9):
			pattern = re.compile('_B0%d_(.*)m.jp2' % i)
			somebands = [
				bandname for bandname in bandnames if
				re.search(pattern, bandname)]
			if len(somebands) > 1:
				heightpres = [
					int(bandname.split("_")[3][:2]) for bandname in somebands]
				gaolfilename = somebands[heightpres.index(min(heightpres))]
				filesign, extend = os.path.splitext(gaolfilename)
				sings = filesign.split("_")
				newfilename = sings[0] + r"_" + sings[1] + r"_" + sings[
					2] + extend
				newgaolfilepath = os.path.join(timedir, newfilename)
				goalfilepath = os.path.join(timedir, gaolfilename)
				if not os.path.exists(newgaolfilepath):
					os.rename(goalfilepath, newgaolfilepath)
			elif len(somebands) == 1:
				gaolfilename = somebands[0]
				filesign, extend = os.path.splitext(gaolfilename)
				sings = filesign.split("_")
				newfilename = sings[0] + r"_" + sings[1] + r"_" + sings[
					2] + extend
				newgaolfilepath = os.path.join(timedir, newfilename)
				goalfilepath = os.path.join(timedir, gaolfilename)
				if not os.path.exists(newgaolfilepath):
					os.rename(goalfilepath, newgaolfilepath)
		return
	
	def ShapeToRaster(self, raspath, rasdir, dsname, layername=None):
		"""栅格转矢量"""
		'''获取源栅格的srs'''
		ras = gdal.Open(raspath)
		rassrsw = ras.GetSpatialRef().ExportToWkt()
		del ras
		'''获取源layer的srs'''
		if layername is None:
			shp = ogr.Open(dsname)
			layer = shp.GetLayer(0)
			layername = layer.GetName()
			shpsrsw = layer.GetSpatialRef().ExportToWkt()
		else:
			shp = ogr.Open(dsname)
			layer = shp.GetLayerByName(layername)
			shpsrsw = layer.GetSpatialRef().ExportToWkt()
			shp.Destroy()
		'''获取源layer所有geom，并转换geom坐标'''
		etjgeometrys = self.SPU.ShpToETJGeometrys(dsname, layername)
		etjgeometrys = self.SPU.ETJGeometrysSrsTransf(
			etjgeometrys, shpsrsw, rassrsw)
		'''创建layer添加geom'''
		newlayername = layername + r"_ras"
		[dsdir, dssign] = os.path.split(dsname)
		[dstdsname, dstlayername] = self.SPU.CreateEmptyShp(
			dsdir, dssign, layername=newlayername, srsstr=rassrsw)
		self.SPU.GeomsUpdataShp(dstdsname, dstlayername, etjgeometrys)
		'''获取矢量标签栅格'''
		raspath = self.SPU.ShapeToRaster(
			raspath, dsname, rasdir, layername=dstlayername)
		'''删除临时layer'''
		shp = ogr.Open(dsname, 1)
		shp.DeleteLayer(dstlayername)
		shp.Destroy()
		return raspath
	
	def BatchDkRaster(self):
		pathss = [
			[
				r"/home/fyy_dapeng/sourcedata/sourceimg/rasterNDVI/T50SKG_2020_0606_0706_0810_2NDVI.tif",
				r"/home/fyy_dapeng/sourcedata/sourceshp/test1/130127高邑县玉米"
			],
			[
				r"/home/fyy_dapeng/sourcedata/sourceimg/rasterNDVI/T50SLH_2020_0606_0706_0810_2NDVI.tif",
				r"/home/fyy_dapeng/sourcedata/sourceshp/test2/130682定州市玉米"
			],
			[
				r"/home/fyy_dapeng/sourcedata/sourceimg/rasterNDVI/T50SMJ_2020_0606_0706_0810_2NDVI.tif",
				r"/home/fyy_dapeng/sourcedata/sourceshp/test3/131022固安县玉米"
			],
			[
				r"/home/fyy_dapeng/sourcedata/sourceimg/rasterNDVI/T50SLJ_2020_0606_0706_0810_2NDVI.tif",
				r"/home/fyy_dapeng/sourcedata/sourceshp/test4/130623涞水县玉米"
			],
		]
		rasdir = r"/home/fyy_dapeng/sourcedata/sourceimg/DK_Raster"
		dkras_paths = [
			self.ShapeToRaster(paths[0], rasdir, paths[1])
			for paths in pathss]
		rass_paths = [
			[
				r"/home/fyy_dapeng/sourcedata/sourceimg/rasterNDVI/T50SKG_2020_0606_0706_0810_2NDVI.tif",
				dkras_paths[0]
			],
			[
				r"/home/fyy_dapeng/sourcedata/sourceimg/rasterNDVI/T50SLH_2020_0606_0706_0810_2NDVI.tif",
				dkras_paths[1]
			],
			[
				r"/home/fyy_dapeng/sourcedata/sourceimg/rasterNDVI/T50SMJ_2020_0606_0706_0810_2NDVI.tif",
				dkras_paths[2]
			],
			[
				r"/home/fyy_dapeng/sourcedata/sourceimg/rasterNDVI/T50SLJ_2020_0606_0706_0810_2NDVI.tif",
				dkras_paths[3]
			],
		]
		rasdkdir = r"/home/fyy_dapeng/sourcedata/sourceimg/dkband__add_30band_raster"
		for rass_path in rass_paths:
			sign1 = os.path.splitext(os.path.split(rass_path[0])[1])[0]
			sign2 = os.path.splitext(os.path.split(rass_path[1])[1])[0]
			sign = sign1 + sign2
			self.RPU.RastersToRaster(rass_path, rasdkdir, sign)
		return
	
	def BatchReshappeRas(self, rasdir, outdir, attrs):
		"""对该目录下的所有栅格依据参数重新缩放，并删除原栅格！"""
		names = os.listdir(rasdir)
		[
			width, height, geot, proj, srsw, drivername, datatype, novalue,
			fileextend] = attrs
		shape = [width, height]
		for name in names:
			raspath = os.path.join(rasdir, name)
			# sign =os.path.splitext(name)[0].split("_")[2]
			signs = os.path.splitext(name)[0].split("_")
			sign = signs[0] + r"_" + signs[1][:8] + r"_" + signs[2]
			arr2ds = self.RasterToReshapeArr2ds(raspath, shape)
			self.RPU.ArrsToRaster(
				arr2ds, outdir, sign, shape, geot, proj, datatype=datatype,
				srswkt=srsw, novalue=novalue)
			
			os.remove(raspath)
		return
	
	def Sentinel2InfoJson(self, citysdir, jsondir, jsonsign):
		"""哨兵图幅信息json文件"""
		'''获取所有jp2文件路径'''
		filepaths = self.FindAllFile(citysdir)
		filepathc = len(filepaths)
		zonenames = []
		for filepathindex in range(filepathc):
			filepath = filepaths[filepathindex]
			filename = os.path.split(filepath)[1]
			filesign = os.path.splitext(filename)[0]
			zonename = filesign.split("_")[0]
			zonenames.append(zonename)
		onlyvaluezonenames = set(zonenames)
		onlyvaluezonenamesindexs = [
			zonenames.index(onlyvaluezonename)
			for onlyvaluezonename in onlyvaluezonenames]
		datalist = []
		for indexitem in onlyvaluezonenamesindexs:
			raspath = filepaths[indexitem]
			zonename = zonenames[indexitem]
			ras = gdal.Open(raspath)
			width, height = ras.RasterXSize, ras.RasterYSize
			geotr = list(ras.GetGeoTransform())
			srsew = ras.GetSpatialRef().ExportToWkt()
			rasinfo = [zonename, width, height, geotr, srsew]
			datalist.append(rasinfo)
		return
	
	def ProvinceShpToCountyShp(self, dsname, fieldname, threshold, raspath,
	                           rasdir):
		[dsname, fieldname] = self.SPU.FieldToLayer(dsname, None, fieldname,
		                                            threshold, "=")
		newraspath = self.SPU.ShapeToRaster(raspath, dsname, rasdir, fieldname)
		rassign = os.path.splitext(os.path.split(raspath)[1])[0].split("_")[0]
		result = os.path.join(rasdir, threshold + r"_" + rassign + "_XY.tif")
		os.rename(newraspath, result)
		ds = ogr.Open(dsname, 1)
		ds.DeleteLayer(fieldname)
		ds.Destroy()
		return newraspath
	
	def BatchProvinceShpToCountyShp(self):
		countys = [
			["130682",
			 r"/home/fyy_dapeng/resultdata/Sentinel2_8Band_10m/定州市/T50SLH/20200606/T50SLH_130682_20200606_B01.tif"],
			["130127",
			 r"/home/fyy_dapeng/resultdata/Sentinel2_8Band_10m/高邑县/T50SKG/20200606/T50SKG_130127_20200606_B01.tif"],
			["131022",
			 r"/home/fyy_dapeng/resultdata/Sentinel2_8Band_10m/固安县/T50SMJ/20200606/T50SMJ_131022_20200606_B01.tif"],
			["130623",
			 r"/home/fyy_dapeng/resultdata/Sentinel2_8Band_10m/涞水县/T50SLJ/20200606/T50SLJ_130623_20200606_B01.tif"],
		]
		hb_county = r"/home/fyy_dapeng/sourcedata/sourceshp/河北县域"
		test_dir = r"/home/fyy_dapeng/resultdata/Sentinel2_County"
		for item in countys:
			qhdmvalue = item[0]
			gy_raspath = item[1]
			newraspath = self.ProvinceShpToCountyShp(
				hb_county, "qhdm", qhdmvalue, gy_raspath, test_dir)
			print(newraspath, ":完成！")
		return
	
	def BatchBLFieldToRaster(self):
		countys = [
			[
				r"/home/fyy_dapeng/sourcedata/sourceshp/实验四县/130682定州市玉米(1)",
				r"/home/fyy_dapeng/resultdata/Sentinel2_8Band_10m/定州市/T50SLH/20200606/T50SLH_130682_20200606_B01.tif"],
			[
				r"/home/fyy_dapeng/sourcedata/sourceshp/实验四县/130127高邑县玉米(1)",
				r"/home/fyy_dapeng/resultdata/Sentinel2_8Band_10m/高邑县/T50SKG/20200606/T50SKG_130127_20200606_B01.tif"],
			[
				r"/home/fyy_dapeng/sourcedata/sourceshp/实验四县/131022固安县玉米",
				r"/home/fyy_dapeng/resultdata/Sentinel2_8Band_10m/固安县/T50SMJ/20200606/T50SMJ_131022_20200606_B01.tif"],
			[
				r"/home/fyy_dapeng/sourcedata/sourceshp/实验四县/130623涞水县玉米(1)",
				r"/home/fyy_dapeng/resultdata/Sentinel2_8Band_10m/涞水县/T50SLJ/20200606/T50SLJ_130623_20200606_B01.tif"],
		]
		fieldname = "BL"
		rasdir = r"/home/fyy_dapeng/resultdata/Sentinel2_BL"
		for item in countys:
			raspath = item[1]
			dsname = item[0]
			outraspath = self.SPU.ShapeFieldvalueToRasterBandValue(
				raspath, rasdir, dsname, None, fieldname)
			sign = os.path.splitext(os.path.split(raspath)[1])[0]
			rasname = sign.split("_")[0] + r"_" + sign.split("_")[
				1] + r"_BL.tif"
			newraspath = os.path.join(rasdir, rasname)
			os.rename(outraspath, newraspath)
			print(newraspath, ":完成！")
		return
	
	@staticmethod
	def GetHeightRasAttrs(rasdir, threshold):
		names = os.listdir(rasdir)
		for name in names:
			raspath = os.path.join(rasdir, name)
			ras = gdal.Open(raspath)
			pre = abs(ras.GetGeoTransform()[1])
			if threshold == pre:
				fileextend = os.path.splitext(name)[1]
				width = ras.RasterXSize
				height = ras.RasterYSize
				geomt = ras.GetGeoTransform()
				proj = ras.GetProjection()
				srsw = ras.GetSpatialRef().ExportToWkt()
				drivername = ras.GetDriver().ShortName
				datatype = ras.GetRasterBand(1).DataType
				novalue = ras.GetRasterBand(1).GetNoDataValue()
				del ras
				return [width, height, geomt, proj, srsw, drivername, datatype,
				        novalue, fileextend]
			del ras
		return
	
	@classmethod
	def RasterWriteTxt(cls, raspath, txtdir, txtsign):
		txtdir = os.path.join(txtdir, txtsign + r".txt")
		if os.path.exists(txtdir):
			print(txtdir, "：文件存在！")
			return
		arr2ds = cls.RasterToArr2ds(raspath)
		ras = gdal.Open(raspath)
		shape = [ras.RasterXSize, ras.RasterYSize]
		geot = ras.GetGeoTransform()
		srsstr = ras.GetSpatialRef().ExportToWkt()
		proj = ras.GetProjectionRef()
		del ras
		print(shape, geot, srsstr, proj)
		num = len(arr2ds)
		c = np.array([arr2ds[0].copy()])
		print("开始拼接数组。。。")
		for i in tqdm(range(1, num)):
			c = np.append(c, np.array([arr2ds[i]]), axis=0)
		print("拼接数组完成！")
		print("开始生成txt文件。。。。")
		pixeltasks = [[x, y] for y in range(shape[1]) for x in range(shape[0])]
		with open(txtdir, mode='a') as txtfile:
			for [xpixel, ypixel] in pixeltasks:
				pixel = c[:, ypixel, xpixel].tolist()
				pixelstr = ""
				pixellenth = len(pixel)
				for index in range(pixellenth):
					if index == pixellenth - 1:
						pixelstr = pixelstr + "%.2f" % pixel[index]
					else:
						pixelstr = pixelstr + "%.2f," % pixel[index]
				txtfile.writelines(pixelstr)
				txtfile.writelines("\n")
		print("生成txt文件结束！")
		return
	
	@classmethod
	def BatchRasterWriteTxt(cls, indir, outdir):
		rasnames = os.listdir(indir)
		print("开始批量生成txt文件...")
		for rasname in tqdm(rasnames):
			print(rasname)
			raspath = os.path.join(indir, rasname)
			txtsign = os.path.splitext(rasname)[0]
			print(txtsign)
			cls.RasterWriteTxt(raspath, outdir, txtsign)
		print("批量生成txt文件结束！")
		return
	
	@staticmethod
	def StrsToTxt(strs, outdir, txtsign):
		print("开始生成txt文件。。。")
		txtpath = os.path.join(outdir, txtsign + r".txt")
		with open(txtpath, mode='a') as txtfile:
			for linestr in tqdm(strs):
				txtfile.writelines(linestr)
				txtfile.writelines("\n")
		print("完成txt文件生成！")
		return
	
	@staticmethod
	def TxtToStrs(txtpath):
		with open(txtpath, mode='r') as txtfile:
			lines = [line.split("\n")[0] for line in txtfile]
		return lines
	
	def ShpGeomFieldToTxt(self, dsname, layername, outdir, fieldname):
		featurejsons = self.SPU.ShpToJson(dsname, layername)
		linestrs = []
		print("开始构建每行字符串。。。")
		for featurejson in tqdm(featurejsons):
			featuredict = json.loads(featurejson)
			print(featuredict)
			fieldvalue = featuredict["properties"][fieldname]
			linestr = "dangpeng.jpg" + " " + "%.2f" % fieldvalue
			polygon = featuredict["geometry"]["coordinates"][0][:-1]
			for point in polygon:
				linestr = linestr + r" " + "%0.6f" % point[0] + r" " + "%0.6f" % \
				          point[1]
			linestrs.append(linestr)
		print("完成每行字符串构建！")
		self.StrsToTxt(linestrs, outdir, layername)
		return
	
	def TxtToShp(self, txtpath, outdir):
		"""未完成"""
		sign = os.path.splitext(os.path.split(txtpath)[1])[0]
		dsname = os.path.join(outdir, sign)
		layername = sign
		with open(txtpath, mode='r') as txtfile:
			lines = [line.split("\n")[0] for line in txtfile]
		feaurevalues = []
		for line in lines:
			strs = line.split(" ")
			fieldvalue = float(strs[1])
			pointc = int(len(strs[2:]) / 2)
			polygon = [
				[float(strs[int(2 + 2 * index)]),
				 float(strs[int(2 + 2 * index + 1)])]
				for index in range(pointc)]
			feaurevalues.append([fieldvalue, polygon])
		self.SPU.CreateEmptyShp(
			dsdir, dssign, layername=None, drivername=None, srsstr=None,
			layerdefn=None, geomtype=None)
		return feaurevalues
	
	@classmethod
	def FeatureargToJFeature(cls, polygon, fieldargs, featureid):
		propertiesdict = cls.FieldargsToPropertiesdict(fieldargs)
		geometrydict = {"type": 'Polygon', "coordinates": polygon}
		featuredict = {
			"type": "Featrue",
			"geometry": geometrydict,
			"properties": propertiesdict,
			"id": featureid}
		return featuredict
	
	@staticmethod
	def FieldargsToPropertiesdict(fieldargs):
		propertiesdict = {}
		for fieldarg in fieldargs:
			[fieldname, fieldvalue] = fieldarg
			propertiesdict[fieldname] = fieldvalue
		print(propertiesdict)
		return propertiesdict
	
	def FromRasterGetAllSlideWins(self, rasfile, params):
		"""获取所有滑窗两个锚点地理坐标"""
		shape = self.RPU.GetShape(rasfile)
		
		[width, height], [stride, winsize] = shape[:-1], params
		[xstride, ystride], [xwinsize, ywinsize] = stride, winsize
		x = xstride - (width - xwinsize) // xstride
		y = ystride - (height - ywinsize) // ystride
		return

	def GetGreenHouseTDS(self, rasfile, rasdir, dsname, shpdir):
		"""制作大棚训练数据集"""
		'''检查栅格文件的名称是否包含中文字符'''
		raspath = self.UTL.GetEnglishNameFile(inpath, rasdir)
		'''检查shp文件坐标系是否与栅格一致'''
		[dsname, layername] = self.UTL.ShpSrsFromRasSrs(raspath, dsname, None, shpdir)
		''''''
		
		rasfiles = self.GetGoalFile(rasfolder, r".tif")
		for rasfile in rasfiles:
			jpgfile = self.RPU.RasterToJPG(rasfile, tdsdir)
			print(jpgfile, ":文件完成！")
		ds.SetSpatialFilterRect()
		return


DPU = DataPU()


class BatchTool:
	
	def __init__(self, spu=SPU, rpu=RPU, dpu=DPU, utl=UTL):
		self.RPU = rpu
		self.DPU = dpu
		self.UTL = utl
		self.SPU = spu

	def BatchShpsToGeomShp(self, shpdir, dstdir):
		"""提取多个shp的geometry，合并为一个shp"""
		shpfoldernames = os.listdir(shpdir)
		dssign = os.path.split(shpdir)[1]
		dstlayername = "pre"
		[shpfolder, newlayername] = self.SPU.CreateEmptyShp(
			dstdir, dssign, layername=dstlayername)
		print("开始生成合并后的shp文件......\n", )
		jgeoms = []
		for shpfoldername in tqdm(shpfoldernames):
			dsname = os.path.join(shpdir, shpfoldername)
			newjgeoms = self.SPU.ShpToETJGeometrys(
				dsname, layername=dstlayername)
			jgeoms = jgeoms + newjgeoms
		self.SPU.GeomsUpdataShp(shpfolder, newlayername, jgeoms)
		print("完成生成合并后的shp文件！")
		return
	
	def BatchBandMergeRaster(self, indir, outdir):
		"""batch有序合成8band raster"""
		dirnames = os.listdir(indir)
		print("批量处理开始......")
		for dirname in dirnames:
			goaldir = os.path.join(indir, dirname)
			if os.path.isdir(goaldir):
				self.RPU.BandMergeRaster(goaldir, outdir)
		print("批量处理结束！")
		return
	
	def BatchUnzipSentinel2(self, zipsdir, unzipsdir):
		"""批量解压哨兵2压缩文件到指定目录下"""
		zippaths = self.UTL.GetGoalFile(zipsdir, r".zip")
		print("开始批量解压哨兵2压缩文件！")
		for zippath in zippaths:
			unzipfolder = self.UTL.UnzipFile(zippath, unzipsdir)
			print(unzipfolder)
		print("完成批量解压哨兵2压缩文件！")
		return
	
	def BatchAlterSentinel2(self, unzipsdir, normfilesdir):
		"""批量提取、修改哨兵2单波段栅格哨兵文件至标准目录下"""
		names = os.listdir(unzipsdir)
		for name in tqdm(names):
			path = os.path.join(unzipsdir, name)
			self.WashDirSaveGoalFiles(path, self.matchstr)
		print("开始批量精选目录中文件。。。")
		foldernames = os.listdir(rasdir)
		for foldername in tqdm(foldernames):
			folder = os.path.join(rasdir, foldername)
			self.ChoiceGoalFile(folder)
		print("完成批量精选目录中文件。。。")
		print("开始批量重新命名文件夹！")
		foldernames = os.listdir(rasdir)
		for name in tqdm(foldernames):
			newname = name.split("_")[5] + r"_" + name.split("_")[6][:8]
			newfolder = os.path.join(rasdir, newname)
			folder = os.path.join(rasdir, name)
			shutil.move(folder, newfolder)
		print("完成批量重新命名文件夹。。。")
		print("开始批量获取不同目录下最高精度栅格参数，并缩放低精度影像！")
		foldernames = os.listdir(rasdir)
		for name in tqdm(foldernames):
			newrasdir = os.path.join(rasdir, name)
			attrs = self.GetHeightRasAttrs(newrasdir, 10)
			self.BatchReshappeRas(newrasdir, newrasdir, attrs)
		print("完成批量获取不同目录下最高精度栅格参数，并缩放低精度影像！")
		return
	
	def BatchSlipRaster(self, rasdir, savedir):
		"""批量拆分栅格"""
		filenames = os.listdir(rasdir)
		for filename in filenames:
			foldername = os.path.splitext(filename)[0]
			folder = os.path.join(savedir, foldername)
			if not os.path.exists(folder):
				os.makedirs(folder)
			raspath = os.path.join(rasdir, filename)
			self.UTL.SplitRaster(raspath, folder)
		return
	
	def BatchLabelmeJsonSort(self, datasetdir, floatjpgpaths, savedir1, savedir2):
		jsonpaths = self.UTL.GetGoalFile(datasetdir, ".json")
		for jsonpath in jsonpaths:
			self.DPU.LabelmeJsonSort(jsonpath, floatjpgpaths, savedir1, savedir2)
		return

BTL = BatchTool()

